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 (Allows +08, without minutes)
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"
1390 s:"([+\-]\\d{2,4})"};
1396 "o = results[", currentGroup, "];\n",
1397 "var sn = o.substring(0,1);\n",
1398 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1399 "var mn = o.substring(4,6) % 60;\n",
1400 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1401 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1411 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1412 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1416 s:String.escape(character)};
1421 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1422 * @return {String} The abbreviated timezone name (e.g. 'CST')
1424 Date.prototype.getTimezone = function() {
1425 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1429 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1430 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1432 Date.prototype.getGMTOffset = function() {
1433 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1434 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1435 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1439 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1440 * @return {String} 2-characters representing hours and 2-characters representing minutes
1441 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1443 Date.prototype.getGMTColonOffset = function() {
1444 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1445 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1447 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1451 * Get the numeric day number of the year, adjusted for leap year.
1452 * @return {Number} 0 through 364 (365 in leap years)
1454 Date.prototype.getDayOfYear = function() {
1456 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1457 for (var i = 0; i < this.getMonth(); ++i) {
1458 num += Date.daysInMonth[i];
1460 return num + this.getDate() - 1;
1464 * Get the string representation of the numeric week number of the year
1465 * (equivalent to the format specifier 'W').
1466 * @return {String} '00' through '52'
1468 Date.prototype.getWeekOfYear = function() {
1469 // Skip to Thursday of this week
1470 var now = this.getDayOfYear() + (4 - this.getDay());
1471 // Find the first Thursday of the year
1472 var jan1 = new Date(this.getFullYear(), 0, 1);
1473 var then = (7 - jan1.getDay() + 4);
1474 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1478 * Whether or not the current date is in a leap year.
1479 * @return {Boolean} True if the current date is in a leap year, else false
1481 Date.prototype.isLeapYear = function() {
1482 var year = this.getFullYear();
1483 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1487 * Get the first day of the current month, adjusted for leap year. The returned value
1488 * is the numeric day index within the week (0-6) which can be used in conjunction with
1489 * the {@link #monthNames} array to retrieve the textual day name.
1492 var dt = new Date('1/10/2007');
1493 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1495 * @return {Number} The day number (0-6)
1497 Date.prototype.getFirstDayOfMonth = function() {
1498 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1499 return (day < 0) ? (day + 7) : day;
1503 * Get the last day of the current month, adjusted for leap year. The returned value
1504 * is the numeric day index within the week (0-6) which can be used in conjunction with
1505 * the {@link #monthNames} array to retrieve the textual day name.
1508 var dt = new Date('1/10/2007');
1509 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1511 * @return {Number} The day number (0-6)
1513 Date.prototype.getLastDayOfMonth = function() {
1514 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1515 return (day < 0) ? (day + 7) : day;
1520 * Get the first date of this date's month
1523 Date.prototype.getFirstDateOfMonth = function() {
1524 return new Date(this.getFullYear(), this.getMonth(), 1);
1528 * Get the last date of this date's month
1531 Date.prototype.getLastDateOfMonth = function() {
1532 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 * Get the number of days in the current month, adjusted for leap year.
1536 * @return {Number} The number of days in the month
1538 Date.prototype.getDaysInMonth = function() {
1539 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1540 return Date.daysInMonth[this.getMonth()];
1544 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1545 * @return {String} 'st, 'nd', 'rd' or 'th'
1547 Date.prototype.getSuffix = function() {
1548 switch (this.getDate()) {
1565 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568 * An array of textual month names.
1569 * Override these values for international dates, for example...
1570 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1589 * An array of textual day names.
1590 * Override these values for international dates, for example...
1591 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1607 Date.monthNumbers = {
1622 * Creates and returns a new Date instance with the exact same date value as the called instance.
1623 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1624 * variable will also be changed. When the intention is to create a new variable that will not
1625 * modify the original instance, you should create a clone.
1627 * Example of correctly cloning a date:
1630 var orig = new Date('10/1/2006');
1633 document.write(orig); //returns 'Thu Oct 05 2006'!
1636 var orig = new Date('10/1/2006');
1637 var copy = orig.clone();
1639 document.write(orig); //returns 'Thu Oct 01 2006'
1641 * @return {Date} The new Date instance
1643 Date.prototype.clone = function() {
1644 return new Date(this.getTime());
1648 * Clears any time information from this date
1649 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1650 @return {Date} this or the clone
1652 Date.prototype.clearTime = function(clone){
1654 return this.clone().clearTime();
1659 this.setMilliseconds(0);
1664 // safari setMonth is broken
1666 Date.brokenSetMonth = Date.prototype.setMonth;
1667 Date.prototype.setMonth = function(num){
1669 var n = Math.ceil(-num);
1670 var back_year = Math.ceil(n/12);
1671 var month = (n % 12) ? 12 - n % 12 : 0 ;
1672 this.setFullYear(this.getFullYear() - back_year);
1673 return Date.brokenSetMonth.call(this, month);
1675 return Date.brokenSetMonth.apply(this, arguments);
1680 /** Date interval constant
1684 /** Date interval constant
1688 /** Date interval constant
1692 /** Date interval constant
1696 /** Date interval constant
1700 /** Date interval constant
1704 /** Date interval constant
1710 * Provides a convenient method of performing basic date arithmetic. This method
1711 * does not modify the Date instance being called - it creates and returns
1712 * a new Date instance containing the resulting date value.
1717 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1718 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1720 //Negative values will subtract correctly:
1721 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1722 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1724 //You can even chain several calls together in one line!
1725 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1726 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729 * @param {String} interval A valid date interval enum value
1730 * @param {Number} value The amount to add to the current date
1731 * @return {Date} The new Date instance
1733 Date.prototype.add = function(interval, value){
1734 var d = this.clone();
1735 if (!interval || value === 0) return d;
1736 switch(interval.toLowerCase()){
1738 d.setMilliseconds(this.getMilliseconds() + value);
1741 d.setSeconds(this.getSeconds() + value);
1744 d.setMinutes(this.getMinutes() + value);
1747 d.setHours(this.getHours() + value);
1750 d.setDate(this.getDate() + value);
1753 var day = this.getDate();
1755 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758 d.setMonth(this.getMonth() + value);
1761 d.setFullYear(this.getFullYear() + value);
1768 * Ext JS Library 1.1.1
1769 * Copyright(c) 2006-2007, Ext JS, LLC.
1771 * Originally Released Under LGPL - original licence link has changed is not relivant.
1774 * <script type="text/javascript">
1778 * @class Roo.lib.Dom
1781 * Dom utils (from YIU afaik)
1786 * Get the view width
1787 * @param {Boolean} full True will get the full document, otherwise it's the view width
1788 * @return {Number} The width
1791 getViewWidth : function(full) {
1792 return full ? this.getDocumentWidth() : this.getViewportWidth();
1795 * Get the view height
1796 * @param {Boolean} full True will get the full document, otherwise it's the view height
1797 * @return {Number} The height
1799 getViewHeight : function(full) {
1800 return full ? this.getDocumentHeight() : this.getViewportHeight();
1803 getDocumentHeight: function() {
1804 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1805 return Math.max(scrollHeight, this.getViewportHeight());
1808 getDocumentWidth: function() {
1809 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1810 return Math.max(scrollWidth, this.getViewportWidth());
1813 getViewportHeight: function() {
1814 var height = self.innerHeight;
1815 var mode = document.compatMode;
1817 if ((mode || Roo.isIE) && !Roo.isOpera) {
1818 height = (mode == "CSS1Compat") ?
1819 document.documentElement.clientHeight :
1820 document.body.clientHeight;
1826 getViewportWidth: function() {
1827 var width = self.innerWidth;
1828 var mode = document.compatMode;
1830 if (mode || Roo.isIE) {
1831 width = (mode == "CSS1Compat") ?
1832 document.documentElement.clientWidth :
1833 document.body.clientWidth;
1838 isAncestor : function(p, c) {
1845 if (p.contains && !Roo.isSafari) {
1846 return p.contains(c);
1847 } else if (p.compareDocumentPosition) {
1848 return !!(p.compareDocumentPosition(c) & 16);
1850 var parent = c.parentNode;
1855 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858 parent = parent.parentNode;
1864 getRegion : function(el) {
1865 return Roo.lib.Region.getRegion(el);
1868 getY : function(el) {
1869 return this.getXY(el)[1];
1872 getX : function(el) {
1873 return this.getXY(el)[0];
1876 getXY : function(el) {
1877 var p, pe, b, scroll, bd = document.body;
1878 el = Roo.getDom(el);
1879 var fly = Roo.lib.AnimBase.fly;
1880 if (el.getBoundingClientRect) {
1881 b = el.getBoundingClientRect();
1882 scroll = fly(document).getScroll();
1883 return [b.left + scroll.left, b.top + scroll.top];
1889 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1896 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1903 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1904 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1911 if (p != el && pe.getStyle('overflow') != 'visible') {
1919 if (Roo.isSafari && hasAbsolute) {
1924 if (Roo.isGecko && !hasAbsolute) {
1926 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1927 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1931 while (p && p != bd) {
1932 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1944 setXY : function(el, xy) {
1945 el = Roo.fly(el, '_setXY');
1947 var pts = el.translatePoints(xy);
1948 if (xy[0] !== false) {
1949 el.dom.style.left = pts.left + "px";
1951 if (xy[1] !== false) {
1952 el.dom.style.top = pts.top + "px";
1956 setX : function(el, x) {
1957 this.setXY(el, [x, false]);
1960 setY : function(el, y) {
1961 this.setXY(el, [false, y]);
1965 * Portions of this file are based on pieces of Yahoo User Interface Library
1966 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1967 * YUI licensed under the BSD License:
1968 * http://developer.yahoo.net/yui/license.txt
1969 * <script type="text/javascript">
1973 Roo.lib.Event = function() {
1974 var loadComplete = false;
1976 var unloadListeners = [];
1978 var onAvailStack = [];
1980 var lastError = null;
1993 startInterval: function() {
1994 if (!this._interval) {
1996 var callback = function() {
1997 self._tryPreloadAttach();
1999 this._interval = setInterval(callback, this.POLL_INTERVAL);
2004 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2005 onAvailStack.push({ id: p_id,
2008 override: p_override,
2009 checkReady: false });
2011 retryCount = this.POLL_RETRYS;
2012 this.startInterval();
2016 addListener: function(el, eventName, fn) {
2017 el = Roo.getDom(el);
2022 if ("unload" == eventName) {
2023 unloadListeners[unloadListeners.length] =
2024 [el, eventName, fn];
2028 var wrappedFn = function(e) {
2029 return fn(Roo.lib.Event.getEvent(e));
2032 var li = [el, eventName, fn, wrappedFn];
2034 var index = listeners.length;
2035 listeners[index] = li;
2037 this.doAdd(el, eventName, wrappedFn, false);
2043 removeListener: function(el, eventName, fn) {
2046 el = Roo.getDom(el);
2049 return this.purgeElement(el, false, eventName);
2053 if ("unload" == eventName) {
2055 for (i = 0,len = unloadListeners.length; i < len; i++) {
2056 var li = unloadListeners[i];
2059 li[1] == eventName &&
2061 unloadListeners.splice(i, 1);
2069 var cacheItem = null;
2072 var index = arguments[3];
2074 if ("undefined" == typeof index) {
2075 index = this._getCacheIndex(el, eventName, fn);
2079 cacheItem = listeners[index];
2082 if (!el || !cacheItem) {
2086 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2088 delete listeners[index][this.WFN];
2089 delete listeners[index][this.FN];
2090 listeners.splice(index, 1);
2097 getTarget: function(ev, resolveTextNode) {
2098 ev = ev.browserEvent || ev;
2099 var t = ev.target || ev.srcElement;
2100 return this.resolveTextNode(t);
2104 resolveTextNode: function(node) {
2105 if (Roo.isSafari && node && 3 == node.nodeType) {
2106 return node.parentNode;
2113 getPageX: function(ev) {
2114 ev = ev.browserEvent || ev;
2116 if (!x && 0 !== x) {
2117 x = ev.clientX || 0;
2120 x += this.getScroll()[1];
2128 getPageY: function(ev) {
2129 ev = ev.browserEvent || ev;
2131 if (!y && 0 !== y) {
2132 y = ev.clientY || 0;
2135 y += this.getScroll()[0];
2144 getXY: function(ev) {
2145 ev = ev.browserEvent || ev;
2146 return [this.getPageX(ev), this.getPageY(ev)];
2150 getRelatedTarget: function(ev) {
2151 ev = ev.browserEvent || ev;
2152 var t = ev.relatedTarget;
2154 if (ev.type == "mouseout") {
2156 } else if (ev.type == "mouseover") {
2161 return this.resolveTextNode(t);
2165 getTime: function(ev) {
2166 ev = ev.browserEvent || ev;
2168 var t = new Date().getTime();
2172 this.lastError = ex;
2181 stopEvent: function(ev) {
2182 this.stopPropagation(ev);
2183 this.preventDefault(ev);
2187 stopPropagation: function(ev) {
2188 ev = ev.browserEvent || ev;
2189 if (ev.stopPropagation) {
2190 ev.stopPropagation();
2192 ev.cancelBubble = true;
2197 preventDefault: function(ev) {
2198 ev = ev.browserEvent || ev;
2199 if(ev.preventDefault) {
2200 ev.preventDefault();
2202 ev.returnValue = false;
2207 getEvent: function(e) {
2208 var ev = e || window.event;
2210 var c = this.getEvent.caller;
2212 ev = c.arguments[0];
2213 if (ev && Event == ev.constructor) {
2223 getCharCode: function(ev) {
2224 ev = ev.browserEvent || ev;
2225 return ev.charCode || ev.keyCode || 0;
2229 _getCacheIndex: function(el, eventName, fn) {
2230 for (var i = 0,len = listeners.length; i < len; ++i) {
2231 var li = listeners[i];
2233 li[this.FN] == fn &&
2234 li[this.EL] == el &&
2235 li[this.TYPE] == eventName) {
2247 getEl: function(id) {
2248 return document.getElementById(id);
2252 clearCache: function() {
2256 _load: function(e) {
2257 loadComplete = true;
2258 var EU = Roo.lib.Event;
2262 EU.doRemove(window, "load", EU._load);
2267 _tryPreloadAttach: function() {
2276 var tryAgain = !loadComplete;
2278 tryAgain = (retryCount > 0);
2283 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2284 var item = onAvailStack[i];
2286 var el = this.getEl(item.id);
2289 if (!item.checkReady ||
2292 (document && document.body)) {
2295 if (item.override) {
2296 if (item.override === true) {
2299 scope = item.override;
2302 item.fn.call(scope, item.obj);
2303 onAvailStack[i] = null;
2306 notAvail.push(item);
2311 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2315 this.startInterval();
2317 clearInterval(this._interval);
2318 this._interval = null;
2321 this.locked = false;
2328 purgeElement: function(el, recurse, eventName) {
2329 var elListeners = this.getListeners(el, eventName);
2331 for (var i = 0,len = elListeners.length; i < len; ++i) {
2332 var l = elListeners[i];
2333 this.removeListener(el, l.type, l.fn);
2337 if (recurse && el && el.childNodes) {
2338 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2339 this.purgeElement(el.childNodes[i], recurse, eventName);
2345 getListeners: function(el, eventName) {
2346 var results = [], searchLists;
2348 searchLists = [listeners, unloadListeners];
2349 } else if (eventName == "unload") {
2350 searchLists = [unloadListeners];
2352 searchLists = [listeners];
2355 for (var j = 0; j < searchLists.length; ++j) {
2356 var searchList = searchLists[j];
2357 if (searchList && searchList.length > 0) {
2358 for (var i = 0,len = searchList.length; i < len; ++i) {
2359 var l = searchList[i];
2360 if (l && l[this.EL] === el &&
2361 (!eventName || eventName === l[this.TYPE])) {
2366 adjust: l[this.ADJ_SCOPE],
2374 return (results.length) ? results : null;
2378 _unload: function(e) {
2380 var EU = Roo.lib.Event, i, j, l, len, index;
2382 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2383 l = unloadListeners[i];
2386 if (l[EU.ADJ_SCOPE]) {
2387 if (l[EU.ADJ_SCOPE] === true) {
2390 scope = l[EU.ADJ_SCOPE];
2393 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2394 unloadListeners[i] = null;
2400 unloadListeners = null;
2402 if (listeners && listeners.length > 0) {
2403 j = listeners.length;
2406 l = listeners[index];
2408 EU.removeListener(l[EU.EL], l[EU.TYPE],
2418 EU.doRemove(window, "unload", EU._unload);
2423 getScroll: function() {
2424 var dd = document.documentElement, db = document.body;
2425 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2426 return [dd.scrollTop, dd.scrollLeft];
2428 return [db.scrollTop, db.scrollLeft];
2435 doAdd: function () {
2436 if (window.addEventListener) {
2437 return function(el, eventName, fn, capture) {
2438 el.addEventListener(eventName, fn, (capture));
2440 } else if (window.attachEvent) {
2441 return function(el, eventName, fn, capture) {
2442 el.attachEvent("on" + eventName, fn);
2451 doRemove: function() {
2452 if (window.removeEventListener) {
2453 return function (el, eventName, fn, capture) {
2454 el.removeEventListener(eventName, fn, (capture));
2456 } else if (window.detachEvent) {
2457 return function (el, eventName, fn) {
2458 el.detachEvent("on" + eventName, fn);
2470 var E = Roo.lib.Event;
2471 E.on = E.addListener;
2472 E.un = E.removeListener;
2474 if (document && document.body) {
2477 E.doAdd(window, "load", E._load);
2479 E.doAdd(window, "unload", E._unload);
2480 E._tryPreloadAttach();
2484 * Portions of this file are based on pieces of Yahoo User Interface Library
2485 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2486 * YUI licensed under the BSD License:
2487 * http://developer.yahoo.net/yui/license.txt
2488 * <script type="text/javascript">
2494 * @class Roo.lib.Ajax
2501 request : function(method, uri, cb, data, options) {
2503 var hs = options.headers;
2506 if(hs.hasOwnProperty(h)){
2507 this.initHeader(h, hs[h], false);
2511 if(options.xmlData){
2512 this.initHeader('Content-Type', 'text/xml', false);
2514 data = options.xmlData;
2518 return this.asyncRequest(method, uri, cb, data);
2521 serializeForm : function(form) {
2522 if(typeof form == 'string') {
2523 form = (document.getElementById(form) || document.forms[form]);
2526 var el, name, val, disabled, data = '', hasSubmit = false;
2527 for (var i = 0; i < form.elements.length; i++) {
2528 el = form.elements[i];
2529 disabled = form.elements[i].disabled;
2530 name = form.elements[i].name;
2531 val = form.elements[i].value;
2533 if (!disabled && name){
2537 case 'select-multiple':
2538 for (var j = 0; j < el.options.length; j++) {
2539 if (el.options[j].selected) {
2541 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2544 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2565 if(hasSubmit == false) {
2566 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2571 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2576 data = data.substr(0, data.length - 1);
2584 useDefaultHeader:true,
2586 defaultPostHeader:'application/x-www-form-urlencoded',
2588 useDefaultXhrHeader:true,
2590 defaultXhrHeader:'XMLHttpRequest',
2592 hasDefaultHeaders:true,
2604 setProgId:function(id)
2606 this.activeX.unshift(id);
2609 setDefaultPostHeader:function(b)
2611 this.useDefaultHeader = b;
2614 setDefaultXhrHeader:function(b)
2616 this.useDefaultXhrHeader = b;
2619 setPollingInterval:function(i)
2621 if (typeof i == 'number' && isFinite(i)) {
2622 this.pollInterval = i;
2626 createXhrObject:function(transactionId)
2632 http = new XMLHttpRequest();
2634 obj = { conn:http, tId:transactionId };
2638 for (var i = 0; i < this.activeX.length; ++i) {
2642 http = new ActiveXObject(this.activeX[i]);
2644 obj = { conn:http, tId:transactionId };
2657 getConnectionObject:function()
2660 var tId = this.transactionId;
2664 o = this.createXhrObject(tId);
2666 this.transactionId++;
2677 asyncRequest:function(method, uri, callback, postData)
2679 var o = this.getConnectionObject();
2685 o.conn.open(method, uri, true);
2687 if (this.useDefaultXhrHeader) {
2688 if (!this.defaultHeaders['X-Requested-With']) {
2689 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2693 if(postData && this.useDefaultHeader){
2694 this.initHeader('Content-Type', this.defaultPostHeader);
2697 if (this.hasDefaultHeaders || this.hasHeaders) {
2701 this.handleReadyState(o, callback);
2702 o.conn.send(postData || null);
2708 handleReadyState:function(o, callback)
2712 if (callback && callback.timeout) {
2713 this.timeout[o.tId] = window.setTimeout(function() {
2714 oConn.abort(o, callback, true);
2715 }, callback.timeout);
2718 this.poll[o.tId] = window.setInterval(
2720 if (o.conn && o.conn.readyState == 4) {
2721 window.clearInterval(oConn.poll[o.tId]);
2722 delete oConn.poll[o.tId];
2724 if(callback && callback.timeout) {
2725 window.clearTimeout(oConn.timeout[o.tId]);
2726 delete oConn.timeout[o.tId];
2729 oConn.handleTransactionResponse(o, callback);
2732 , this.pollInterval);
2735 handleTransactionResponse:function(o, callback, isAbort)
2739 this.releaseObject(o);
2743 var httpStatus, responseObject;
2747 if (o.conn.status !== undefined && o.conn.status != 0) {
2748 httpStatus = o.conn.status;
2760 if (httpStatus >= 200 && httpStatus < 300) {
2761 responseObject = this.createResponseObject(o, callback.argument);
2762 if (callback.success) {
2763 if (!callback.scope) {
2764 callback.success(responseObject);
2769 callback.success.apply(callback.scope, [responseObject]);
2774 switch (httpStatus) {
2782 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2783 if (callback.failure) {
2784 if (!callback.scope) {
2785 callback.failure(responseObject);
2788 callback.failure.apply(callback.scope, [responseObject]);
2793 responseObject = this.createResponseObject(o, callback.argument);
2794 if (callback.failure) {
2795 if (!callback.scope) {
2796 callback.failure(responseObject);
2799 callback.failure.apply(callback.scope, [responseObject]);
2805 this.releaseObject(o);
2806 responseObject = null;
2809 createResponseObject:function(o, callbackArg)
2816 var headerStr = o.conn.getAllResponseHeaders();
2817 var header = headerStr.split('\n');
2818 for (var i = 0; i < header.length; i++) {
2819 var delimitPos = header[i].indexOf(':');
2820 if (delimitPos != -1) {
2821 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2829 obj.status = o.conn.status;
2830 obj.statusText = o.conn.statusText;
2831 obj.getResponseHeader = headerObj;
2832 obj.getAllResponseHeaders = headerStr;
2833 obj.responseText = o.conn.responseText;
2834 obj.responseXML = o.conn.responseXML;
2836 if (typeof callbackArg !== undefined) {
2837 obj.argument = callbackArg;
2843 createExceptionObject:function(tId, callbackArg, isAbort)
2846 var COMM_ERROR = 'communication failure';
2847 var ABORT_CODE = -1;
2848 var ABORT_ERROR = 'transaction aborted';
2854 obj.status = ABORT_CODE;
2855 obj.statusText = ABORT_ERROR;
2858 obj.status = COMM_CODE;
2859 obj.statusText = COMM_ERROR;
2863 obj.argument = callbackArg;
2869 initHeader:function(label, value, isDefault)
2871 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2873 if (headerObj[label] === undefined) {
2874 headerObj[label] = value;
2879 headerObj[label] = value + "," + headerObj[label];
2883 this.hasDefaultHeaders = true;
2886 this.hasHeaders = true;
2891 setHeader:function(o)
2893 if (this.hasDefaultHeaders) {
2894 for (var prop in this.defaultHeaders) {
2895 if (this.defaultHeaders.hasOwnProperty(prop)) {
2896 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2901 if (this.hasHeaders) {
2902 for (var prop in this.headers) {
2903 if (this.headers.hasOwnProperty(prop)) {
2904 o.conn.setRequestHeader(prop, this.headers[prop]);
2908 this.hasHeaders = false;
2912 resetDefaultHeaders:function() {
2913 delete this.defaultHeaders;
2914 this.defaultHeaders = {};
2915 this.hasDefaultHeaders = false;
2918 abort:function(o, callback, isTimeout)
2920 if(this.isCallInProgress(o)) {
2922 window.clearInterval(this.poll[o.tId]);
2923 delete this.poll[o.tId];
2925 delete this.timeout[o.tId];
2928 this.handleTransactionResponse(o, callback, true);
2938 isCallInProgress:function(o)
2941 return o.conn.readyState != 4 && o.conn.readyState != 0;
2950 releaseObject:function(o)
2959 'MSXML2.XMLHTTP.3.0',
2967 * Portions of this file are based on pieces of Yahoo User Interface Library
2968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2969 * YUI licensed under the BSD License:
2970 * http://developer.yahoo.net/yui/license.txt
2971 * <script type="text/javascript">
2975 Roo.lib.Region = function(t, r, b, l) {
2985 Roo.lib.Region.prototype = {
2986 contains : function(region) {
2987 return ( region.left >= this.left &&
2988 region.right <= this.right &&
2989 region.top >= this.top &&
2990 region.bottom <= this.bottom );
2994 getArea : function() {
2995 return ( (this.bottom - this.top) * (this.right - this.left) );
2998 intersect : function(region) {
2999 var t = Math.max(this.top, region.top);
3000 var r = Math.min(this.right, region.right);
3001 var b = Math.min(this.bottom, region.bottom);
3002 var l = Math.max(this.left, region.left);
3004 if (b >= t && r >= l) {
3005 return new Roo.lib.Region(t, r, b, l);
3010 union : function(region) {
3011 var t = Math.min(this.top, region.top);
3012 var r = Math.max(this.right, region.right);
3013 var b = Math.max(this.bottom, region.bottom);
3014 var l = Math.min(this.left, region.left);
3016 return new Roo.lib.Region(t, r, b, l);
3019 adjust : function(t, l, b, r) {
3028 Roo.lib.Region.getRegion = function(el) {
3029 var p = Roo.lib.Dom.getXY(el);
3032 var r = p[0] + el.offsetWidth;
3033 var b = p[1] + el.offsetHeight;
3036 return new Roo.lib.Region(t, r, b, l);
3039 * Portions of this file are based on pieces of Yahoo User Interface Library
3040 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3041 * YUI licensed under the BSD License:
3042 * http://developer.yahoo.net/yui/license.txt
3043 * <script type="text/javascript">
3046 //@@dep Roo.lib.Region
3049 Roo.lib.Point = function(x, y) {
3050 if (x instanceof Array) {
3054 this.x = this.right = this.left = this[0] = x;
3055 this.y = this.top = this.bottom = this[1] = y;
3058 Roo.lib.Point.prototype = new Roo.lib.Region();
3060 * Portions of this file are based on pieces of Yahoo User Interface Library
3061 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3062 * YUI licensed under the BSD License:
3063 * http://developer.yahoo.net/yui/license.txt
3064 * <script type="text/javascript">
3071 scroll : function(el, args, duration, easing, cb, scope) {
3072 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3075 motion : function(el, args, duration, easing, cb, scope) {
3076 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3079 color : function(el, args, duration, easing, cb, scope) {
3080 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3083 run : function(el, args, duration, easing, cb, scope, type) {
3084 type = type || Roo.lib.AnimBase;
3085 if (typeof easing == "string") {
3086 easing = Roo.lib.Easing[easing];
3088 var anim = new type(el, args, duration, easing);
3089 anim.animateX(function() {
3090 Roo.callback(cb, scope);
3096 * Portions of this file are based on pieces of Yahoo User Interface Library
3097 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3098 * YUI licensed under the BSD License:
3099 * http://developer.yahoo.net/yui/license.txt
3100 * <script type="text/javascript">
3108 if (!libFlyweight) {
3109 libFlyweight = new Roo.Element.Flyweight();
3111 libFlyweight.dom = el;
3112 return libFlyweight;
3115 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3119 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3121 this.init(el, attributes, duration, method);
3125 Roo.lib.AnimBase.fly = fly;
3129 Roo.lib.AnimBase.prototype = {
3131 toString: function() {
3132 var el = this.getEl();
3133 var id = el.id || el.tagName;
3134 return ("Anim " + id);
3138 noNegatives: /width|height|opacity|padding/i,
3139 offsetAttribute: /^((width|height)|(top|left))$/,
3140 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3141 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3145 doMethod: function(attr, start, end) {
3146 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3150 setAttribute: function(attr, val, unit) {
3151 if (this.patterns.noNegatives.test(attr)) {
3152 val = (val > 0) ? val : 0;
3155 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3159 getAttribute: function(attr) {
3160 var el = this.getEl();
3161 var val = fly(el).getStyle(attr);
3163 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3164 return parseFloat(val);
3167 var a = this.patterns.offsetAttribute.exec(attr) || [];
3168 var pos = !!( a[3] );
3169 var box = !!( a[2] );
3172 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3173 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3182 getDefaultUnit: function(attr) {
3183 if (this.patterns.defaultUnit.test(attr)) {
3190 animateX : function(callback, scope) {
3191 var f = function() {
3192 this.onComplete.removeListener(f);
3193 if (typeof callback == "function") {
3194 callback.call(scope || this, this);
3197 this.onComplete.addListener(f, this);
3202 setRuntimeAttribute: function(attr) {
3205 var attributes = this.attributes;
3207 this.runtimeAttributes[attr] = {};
3209 var isset = function(prop) {
3210 return (typeof prop !== 'undefined');
3213 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3217 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3220 if (isset(attributes[attr]['to'])) {
3221 end = attributes[attr]['to'];
3222 } else if (isset(attributes[attr]['by'])) {
3223 if (start.constructor == Array) {
3225 for (var i = 0, len = start.length; i < len; ++i) {
3226 end[i] = start[i] + attributes[attr]['by'][i];
3229 end = start + attributes[attr]['by'];
3233 this.runtimeAttributes[attr].start = start;
3234 this.runtimeAttributes[attr].end = end;
3237 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3241 init: function(el, attributes, duration, method) {
3243 var isAnimated = false;
3246 var startTime = null;
3249 var actualFrames = 0;
3252 el = Roo.getDom(el);
3255 this.attributes = attributes || {};
3258 this.duration = duration || 1;
3261 this.method = method || Roo.lib.Easing.easeNone;
3264 this.useSeconds = true;
3267 this.currentFrame = 0;
3270 this.totalFrames = Roo.lib.AnimMgr.fps;
3273 this.getEl = function() {
3278 this.isAnimated = function() {
3283 this.getStartTime = function() {
3287 this.runtimeAttributes = {};
3290 this.animate = function() {
3291 if (this.isAnimated()) {
3295 this.currentFrame = 0;
3297 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3299 Roo.lib.AnimMgr.registerElement(this);
3303 this.stop = function(finish) {
3305 this.currentFrame = this.totalFrames;
3306 this._onTween.fire();
3308 Roo.lib.AnimMgr.stop(this);
3311 var onStart = function() {
3312 this.onStart.fire();
3314 this.runtimeAttributes = {};
3315 for (var attr in this.attributes) {
3316 this.setRuntimeAttribute(attr);
3321 startTime = new Date();
3325 var onTween = function() {
3327 duration: new Date() - this.getStartTime(),
3328 currentFrame: this.currentFrame
3331 data.toString = function() {
3333 'duration: ' + data.duration +
3334 ', currentFrame: ' + data.currentFrame
3338 this.onTween.fire(data);
3340 var runtimeAttributes = this.runtimeAttributes;
3342 for (var attr in runtimeAttributes) {
3343 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3349 var onComplete = function() {
3350 var actual_duration = (new Date() - startTime) / 1000 ;
3353 duration: actual_duration,
3354 frames: actualFrames,
3355 fps: actualFrames / actual_duration
3358 data.toString = function() {
3360 'duration: ' + data.duration +
3361 ', frames: ' + data.frames +
3362 ', fps: ' + data.fps
3368 this.onComplete.fire(data);
3372 this._onStart = new Roo.util.Event(this);
3373 this.onStart = new Roo.util.Event(this);
3374 this.onTween = new Roo.util.Event(this);
3375 this._onTween = new Roo.util.Event(this);
3376 this.onComplete = new Roo.util.Event(this);
3377 this._onComplete = new Roo.util.Event(this);
3378 this._onStart.addListener(onStart);
3379 this._onTween.addListener(onTween);
3380 this._onComplete.addListener(onComplete);
3385 * Portions of this file are based on pieces of Yahoo User Interface Library
3386 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3387 * YUI licensed under the BSD License:
3388 * http://developer.yahoo.net/yui/license.txt
3389 * <script type="text/javascript">
3393 Roo.lib.AnimMgr = new function() {
3410 this.registerElement = function(tween) {
3411 queue[queue.length] = tween;
3413 tween._onStart.fire();
3418 this.unRegister = function(tween, index) {
3419 tween._onComplete.fire();
3420 index = index || getIndex(tween);
3422 queue.splice(index, 1);
3426 if (tweenCount <= 0) {
3432 this.start = function() {
3433 if (thread === null) {
3434 thread = setInterval(this.run, this.delay);
3439 this.stop = function(tween) {
3441 clearInterval(thread);
3443 for (var i = 0, len = queue.length; i < len; ++i) {
3444 if (queue[0].isAnimated()) {
3445 this.unRegister(queue[0], 0);
3454 this.unRegister(tween);
3459 this.run = function() {
3460 for (var i = 0, len = queue.length; i < len; ++i) {
3461 var tween = queue[i];
3462 if (!tween || !tween.isAnimated()) {
3466 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3468 tween.currentFrame += 1;
3470 if (tween.useSeconds) {
3471 correctFrame(tween);
3473 tween._onTween.fire();
3476 Roo.lib.AnimMgr.stop(tween, i);
3481 var getIndex = function(anim) {
3482 for (var i = 0, len = queue.length; i < len; ++i) {
3483 if (queue[i] == anim) {
3491 var correctFrame = function(tween) {
3492 var frames = tween.totalFrames;
3493 var frame = tween.currentFrame;
3494 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3495 var elapsed = (new Date() - tween.getStartTime());
3498 if (elapsed < tween.duration * 1000) {
3499 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3501 tweak = frames - (frame + 1);
3503 if (tweak > 0 && isFinite(tweak)) {
3504 if (tween.currentFrame + tweak >= frames) {
3505 tweak = frames - (frame + 1);
3508 tween.currentFrame += tweak;
3512 * Portions of this file are based on pieces of Yahoo User Interface Library
3513 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3514 * YUI licensed under the BSD License:
3515 * http://developer.yahoo.net/yui/license.txt
3516 * <script type="text/javascript">
3519 Roo.lib.Bezier = new function() {
3521 this.getPosition = function(points, t) {
3522 var n = points.length;
3525 for (var i = 0; i < n; ++i) {
3526 tmp[i] = [points[i][0], points[i][1]];
3529 for (var j = 1; j < n; ++j) {
3530 for (i = 0; i < n - j; ++i) {
3531 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3532 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3536 return [ tmp[0][0], tmp[0][1] ];
3540 * Portions of this file are based on pieces of Yahoo User Interface Library
3541 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3542 * YUI licensed under the BSD License:
3543 * http://developer.yahoo.net/yui/license.txt
3544 * <script type="text/javascript">
3549 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3550 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3553 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3555 var fly = Roo.lib.AnimBase.fly;
3557 var superclass = Y.ColorAnim.superclass;
3558 var proto = Y.ColorAnim.prototype;
3560 proto.toString = function() {
3561 var el = this.getEl();
3562 var id = el.id || el.tagName;
3563 return ("ColorAnim " + id);
3566 proto.patterns.color = /color$/i;
3567 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3568 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3569 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3570 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3573 proto.parseColor = function(s) {
3574 if (s.length == 3) {
3578 var c = this.patterns.hex.exec(s);
3579 if (c && c.length == 4) {
3580 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3583 c = this.patterns.rgb.exec(s);
3584 if (c && c.length == 4) {
3585 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3588 c = this.patterns.hex3.exec(s);
3589 if (c && c.length == 4) {
3590 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3595 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3596 proto.getAttribute = function(attr) {
3597 var el = this.getEl();
3598 if (this.patterns.color.test(attr)) {
3599 var val = fly(el).getStyle(attr);
3601 if (this.patterns.transparent.test(val)) {
3602 var parent = el.parentNode;
3603 val = fly(parent).getStyle(attr);
3605 while (parent && this.patterns.transparent.test(val)) {
3606 parent = parent.parentNode;
3607 val = fly(parent).getStyle(attr);
3608 if (parent.tagName.toUpperCase() == 'HTML') {
3614 val = superclass.getAttribute.call(this, attr);
3619 proto.getAttribute = function(attr) {
3620 var el = this.getEl();
3621 if (this.patterns.color.test(attr)) {
3622 var val = fly(el).getStyle(attr);
3624 if (this.patterns.transparent.test(val)) {
3625 var parent = el.parentNode;
3626 val = fly(parent).getStyle(attr);
3628 while (parent && this.patterns.transparent.test(val)) {
3629 parent = parent.parentNode;
3630 val = fly(parent).getStyle(attr);
3631 if (parent.tagName.toUpperCase() == 'HTML') {
3637 val = superclass.getAttribute.call(this, attr);
3643 proto.doMethod = function(attr, start, end) {
3646 if (this.patterns.color.test(attr)) {
3648 for (var i = 0, len = start.length; i < len; ++i) {
3649 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3652 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3655 val = superclass.doMethod.call(this, attr, start, end);
3661 proto.setRuntimeAttribute = function(attr) {
3662 superclass.setRuntimeAttribute.call(this, attr);
3664 if (this.patterns.color.test(attr)) {
3665 var attributes = this.attributes;
3666 var start = this.parseColor(this.runtimeAttributes[attr].start);
3667 var end = this.parseColor(this.runtimeAttributes[attr].end);
3669 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3670 end = this.parseColor(attributes[attr].by);
3672 for (var i = 0, len = start.length; i < len; ++i) {
3673 end[i] = start[i] + end[i];
3677 this.runtimeAttributes[attr].start = start;
3678 this.runtimeAttributes[attr].end = end;
3684 * Portions of this file are based on pieces of Yahoo User Interface Library
3685 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3686 * YUI licensed under the BSD License:
3687 * http://developer.yahoo.net/yui/license.txt
3688 * <script type="text/javascript">
3694 easeNone: function (t, b, c, d) {
3695 return c * t / d + b;
3699 easeIn: function (t, b, c, d) {
3700 return c * (t /= d) * t + b;
3704 easeOut: function (t, b, c, d) {
3705 return -c * (t /= d) * (t - 2) + b;
3709 easeBoth: function (t, b, c, d) {
3710 if ((t /= d / 2) < 1) {
3711 return c / 2 * t * t + b;
3714 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3718 easeInStrong: function (t, b, c, d) {
3719 return c * (t /= d) * t * t * t + b;
3723 easeOutStrong: function (t, b, c, d) {
3724 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3728 easeBothStrong: function (t, b, c, d) {
3729 if ((t /= d / 2) < 1) {
3730 return c / 2 * t * t * t * t + b;
3733 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3738 elasticIn: function (t, b, c, d, a, p) {
3742 if ((t /= d) == 1) {
3749 if (!a || a < Math.abs(c)) {
3754 var s = p / (2 * Math.PI) * Math.asin(c / a);
3757 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3761 elasticOut: function (t, b, c, d, a, p) {
3765 if ((t /= d) == 1) {
3772 if (!a || a < Math.abs(c)) {
3777 var s = p / (2 * Math.PI) * Math.asin(c / a);
3780 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3784 elasticBoth: function (t, b, c, d, a, p) {
3789 if ((t /= d / 2) == 2) {
3797 if (!a || a < Math.abs(c)) {
3802 var s = p / (2 * Math.PI) * Math.asin(c / a);
3806 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3807 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3809 return a * Math.pow(2, -10 * (t -= 1)) *
3810 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3815 backIn: function (t, b, c, d, s) {
3816 if (typeof s == 'undefined') {
3819 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3823 backOut: function (t, b, c, d, s) {
3824 if (typeof s == 'undefined') {
3827 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3831 backBoth: function (t, b, c, d, s) {
3832 if (typeof s == 'undefined') {
3836 if ((t /= d / 2 ) < 1) {
3837 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3839 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3843 bounceIn: function (t, b, c, d) {
3844 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3848 bounceOut: function (t, b, c, d) {
3849 if ((t /= d) < (1 / 2.75)) {
3850 return c * (7.5625 * t * t) + b;
3851 } else if (t < (2 / 2.75)) {
3852 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3853 } else if (t < (2.5 / 2.75)) {
3854 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3856 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3860 bounceBoth: function (t, b, c, d) {
3862 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3864 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3867 * Portions of this file are based on pieces of Yahoo User Interface Library
3868 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3869 * YUI licensed under the BSD License:
3870 * http://developer.yahoo.net/yui/license.txt
3871 * <script type="text/javascript">
3875 Roo.lib.Motion = function(el, attributes, duration, method) {
3877 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3881 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3885 var superclass = Y.Motion.superclass;
3886 var proto = Y.Motion.prototype;
3888 proto.toString = function() {
3889 var el = this.getEl();
3890 var id = el.id || el.tagName;
3891 return ("Motion " + id);
3894 proto.patterns.points = /^points$/i;
3896 proto.setAttribute = function(attr, val, unit) {
3897 if (this.patterns.points.test(attr)) {
3898 unit = unit || 'px';
3899 superclass.setAttribute.call(this, 'left', val[0], unit);
3900 superclass.setAttribute.call(this, 'top', val[1], unit);
3902 superclass.setAttribute.call(this, attr, val, unit);
3906 proto.getAttribute = function(attr) {
3907 if (this.patterns.points.test(attr)) {
3909 superclass.getAttribute.call(this, 'left'),
3910 superclass.getAttribute.call(this, 'top')
3913 val = superclass.getAttribute.call(this, attr);
3919 proto.doMethod = function(attr, start, end) {
3922 if (this.patterns.points.test(attr)) {
3923 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3924 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3926 val = superclass.doMethod.call(this, attr, start, end);
3931 proto.setRuntimeAttribute = function(attr) {
3932 if (this.patterns.points.test(attr)) {
3933 var el = this.getEl();
3934 var attributes = this.attributes;
3936 var control = attributes['points']['control'] || [];
3940 if (control.length > 0 && !(control[0] instanceof Array)) {
3941 control = [control];
3944 for (i = 0,len = control.length; i < len; ++i) {
3945 tmp[i] = control[i];
3950 Roo.fly(el).position();
3952 if (isset(attributes['points']['from'])) {
3953 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3956 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3959 start = this.getAttribute('points');
3962 if (isset(attributes['points']['to'])) {
3963 end = translateValues.call(this, attributes['points']['to'], start);
3965 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3966 for (i = 0,len = control.length; i < len; ++i) {
3967 control[i] = translateValues.call(this, control[i], start);
3971 } else if (isset(attributes['points']['by'])) {
3972 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3974 for (i = 0,len = control.length; i < len; ++i) {
3975 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3979 this.runtimeAttributes[attr] = [start];
3981 if (control.length > 0) {
3982 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3985 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3988 superclass.setRuntimeAttribute.call(this, attr);
3992 var translateValues = function(val, start) {
3993 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3994 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3999 var isset = function(prop) {
4000 return (typeof prop !== 'undefined');
4004 * Portions of this file are based on pieces of Yahoo User Interface Library
4005 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4006 * YUI licensed under the BSD License:
4007 * http://developer.yahoo.net/yui/license.txt
4008 * <script type="text/javascript">
4012 Roo.lib.Scroll = function(el, attributes, duration, method) {
4014 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4018 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4022 var superclass = Y.Scroll.superclass;
4023 var proto = Y.Scroll.prototype;
4025 proto.toString = function() {
4026 var el = this.getEl();
4027 var id = el.id || el.tagName;
4028 return ("Scroll " + id);
4031 proto.doMethod = function(attr, start, end) {
4034 if (attr == 'scroll') {
4036 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4037 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4041 val = superclass.doMethod.call(this, attr, start, end);
4046 proto.getAttribute = function(attr) {
4048 var el = this.getEl();
4050 if (attr == 'scroll') {
4051 val = [ el.scrollLeft, el.scrollTop ];
4053 val = superclass.getAttribute.call(this, attr);
4059 proto.setAttribute = function(attr, val, unit) {
4060 var el = this.getEl();
4062 if (attr == 'scroll') {
4063 el.scrollLeft = val[0];
4064 el.scrollTop = val[1];
4066 superclass.setAttribute.call(this, attr, val, unit);
4072 * Ext JS Library 1.1.1
4073 * Copyright(c) 2006-2007, Ext JS, LLC.
4075 * Originally Released Under LGPL - original licence link has changed is not relivant.
4078 * <script type="text/javascript">
4082 // nasty IE9 hack - what a pile of crap that is..
4084 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4085 Range.prototype.createContextualFragment = function (html) {
4086 var doc = window.document;
4087 var container = doc.createElement("div");
4088 container.innerHTML = html;
4089 var frag = doc.createDocumentFragment(), n;
4090 while ((n = container.firstChild)) {
4091 frag.appendChild(n);
4098 * @class Roo.DomHelper
4099 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4100 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4103 Roo.DomHelper = function(){
4104 var tempTableEl = null;
4105 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4106 var tableRe = /^table|tbody|tr|td$/i;
4108 // build as innerHTML where available
4110 var createHtml = function(o){
4111 if(typeof o == 'string'){
4120 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4121 if(attr == "style"){
4123 if(typeof s == "function"){
4126 if(typeof s == "string"){
4127 b += ' style="' + s + '"';
4128 }else if(typeof s == "object"){
4131 if(typeof s[key] != "function"){
4132 b += key + ":" + s[key] + ";";
4139 b += ' class="' + o["cls"] + '"';
4140 }else if(attr == "htmlFor"){
4141 b += ' for="' + o["htmlFor"] + '"';
4143 b += " " + attr + '="' + o[attr] + '"';
4147 if(emptyTags.test(o.tag)){
4151 var cn = o.children || o.cn;
4153 //http://bugs.kde.org/show_bug.cgi?id=71506
4154 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4155 for(var i = 0, len = cn.length; i < len; i++) {
4156 b += createHtml(cn[i], b);
4159 b += createHtml(cn, b);
4165 b += "</" + o.tag + ">";
4172 var createDom = function(o, parentNode){
4174 // defininition craeted..
4176 if (o.ns && o.ns != 'html') {
4178 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4179 xmlns[o.ns] = o.xmlns;
4182 if (typeof(xmlns[o.ns]) == 'undefined') {
4183 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4189 if (typeof(o) == 'string') {
4190 return parentNode.appendChild(document.createTextNode(o));
4192 o.tag = o.tag || div;
4193 if (o.ns && Roo.isIE) {
4195 o.tag = o.ns + ':' + o.tag;
4198 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4199 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4202 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4203 attr == "style" || typeof o[attr] == "function") continue;
4205 if(attr=="cls" && Roo.isIE){
4206 el.className = o["cls"];
4208 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4209 else el[attr] = o[attr];
4212 Roo.DomHelper.applyStyles(el, o.style);
4213 var cn = o.children || o.cn;
4215 //http://bugs.kde.org/show_bug.cgi?id=71506
4216 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4217 for(var i = 0, len = cn.length; i < len; i++) {
4218 createDom(cn[i], el);
4225 el.innerHTML = o.html;
4228 parentNode.appendChild(el);
4233 var ieTable = function(depth, s, h, e){
4234 tempTableEl.innerHTML = [s, h, e].join('');
4235 var i = -1, el = tempTableEl;
4242 // kill repeat to save bytes
4246 tbe = '</tbody>'+te,
4252 * Nasty code for IE's broken table implementation
4254 var insertIntoTable = function(tag, where, el, html){
4256 tempTableEl = document.createElement('div');
4261 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4264 if(where == 'beforebegin'){
4268 before = el.nextSibling;
4271 node = ieTable(4, trs, html, tre);
4273 else if(tag == 'tr'){
4274 if(where == 'beforebegin'){
4277 node = ieTable(3, tbs, html, tbe);
4278 } else if(where == 'afterend'){
4279 before = el.nextSibling;
4281 node = ieTable(3, tbs, html, tbe);
4282 } else{ // INTO a TR
4283 if(where == 'afterbegin'){
4284 before = el.firstChild;
4286 node = ieTable(4, trs, html, tre);
4288 } else if(tag == 'tbody'){
4289 if(where == 'beforebegin'){
4292 node = ieTable(2, ts, html, te);
4293 } else if(where == 'afterend'){
4294 before = el.nextSibling;
4296 node = ieTable(2, ts, html, te);
4298 if(where == 'afterbegin'){
4299 before = el.firstChild;
4301 node = ieTable(3, tbs, html, tbe);
4304 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4307 if(where == 'afterbegin'){
4308 before = el.firstChild;
4310 node = ieTable(2, ts, html, te);
4312 el.insertBefore(node, before);
4317 /** True to force the use of DOM instead of html fragments @type Boolean */
4321 * Returns the markup for the passed Element(s) config
4322 * @param {Object} o The Dom object spec (and children)
4325 markup : function(o){
4326 return createHtml(o);
4330 * Applies a style specification to an element
4331 * @param {String/HTMLElement} el The element to apply styles to
4332 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4333 * a function which returns such a specification.
4335 applyStyles : function(el, styles){
4338 if(typeof styles == "string"){
4339 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4341 while ((matches = re.exec(styles)) != null){
4342 el.setStyle(matches[1], matches[2]);
4344 }else if (typeof styles == "object"){
4345 for (var style in styles){
4346 el.setStyle(style, styles[style]);
4348 }else if (typeof styles == "function"){
4349 Roo.DomHelper.applyStyles(el, styles.call());
4355 * Inserts an HTML fragment into the Dom
4356 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4357 * @param {HTMLElement} el The context element
4358 * @param {String} html The HTML fragmenet
4359 * @return {HTMLElement} The new node
4361 insertHtml : function(where, el, html){
4362 where = where.toLowerCase();
4363 if(el.insertAdjacentHTML){
4364 if(tableRe.test(el.tagName)){
4366 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4372 el.insertAdjacentHTML('BeforeBegin', html);
4373 return el.previousSibling;
4375 el.insertAdjacentHTML('AfterBegin', html);
4376 return el.firstChild;
4378 el.insertAdjacentHTML('BeforeEnd', html);
4379 return el.lastChild;
4381 el.insertAdjacentHTML('AfterEnd', html);
4382 return el.nextSibling;
4384 throw 'Illegal insertion point -> "' + where + '"';
4386 var range = el.ownerDocument.createRange();
4390 range.setStartBefore(el);
4391 frag = range.createContextualFragment(html);
4392 el.parentNode.insertBefore(frag, el);
4393 return el.previousSibling;
4396 range.setStartBefore(el.firstChild);
4397 frag = range.createContextualFragment(html);
4398 el.insertBefore(frag, el.firstChild);
4399 return el.firstChild;
4401 el.innerHTML = html;
4402 return el.firstChild;
4406 range.setStartAfter(el.lastChild);
4407 frag = range.createContextualFragment(html);
4408 el.appendChild(frag);
4409 return el.lastChild;
4411 el.innerHTML = html;
4412 return el.lastChild;
4415 range.setStartAfter(el);
4416 frag = range.createContextualFragment(html);
4417 el.parentNode.insertBefore(frag, el.nextSibling);
4418 return el.nextSibling;
4420 throw 'Illegal insertion point -> "' + where + '"';
4424 * Creates new Dom element(s) and inserts them before el
4425 * @param {String/HTMLElement/Element} el The context element
4426 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4427 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4428 * @return {HTMLElement/Roo.Element} The new node
4430 insertBefore : function(el, o, returnElement){
4431 return this.doInsert(el, o, returnElement, "beforeBegin");
4435 * Creates new Dom element(s) and inserts them after el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object} o The Dom object spec (and children)
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertAfter : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4446 * Creates new Dom element(s) and inserts them as the first child of el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertFirst : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterBegin");
4457 doInsert : function(el, o, returnElement, pos, sibling){
4458 el = Roo.getDom(el);
4460 if(this.useDom || o.ns){
4461 newNode = createDom(o, null);
4462 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4464 var html = createHtml(o);
4465 newNode = this.insertHtml(pos, el, html);
4467 return returnElement ? Roo.get(newNode, true) : newNode;
4471 * Creates new Dom element(s) and appends them to el
4472 * @param {String/HTMLElement/Element} el The context element
4473 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4474 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475 * @return {HTMLElement/Roo.Element} The new node
4477 append : function(el, o, returnElement){
4478 el = Roo.getDom(el);
4480 if(this.useDom || o.ns){
4481 newNode = createDom(o, null);
4482 el.appendChild(newNode);
4484 var html = createHtml(o);
4485 newNode = this.insertHtml("beforeEnd", el, html);
4487 return returnElement ? Roo.get(newNode, true) : newNode;
4491 * Creates new Dom element(s) and overwrites the contents of el with them
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 overwrite : function(el, o, returnElement){
4498 el = Roo.getDom(el);
4501 while (el.childNodes.length) {
4502 el.removeChild(el.firstChild);
4506 el.innerHTML = createHtml(o);
4509 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4513 * Creates a new Roo.DomHelper.Template from the Dom object spec
4514 * @param {Object} o The Dom object spec (and children)
4515 * @return {Roo.DomHelper.Template} The new template
4517 createTemplate : function(o){
4518 var html = createHtml(o);
4519 return new Roo.Template(html);
4525 * Ext JS Library 1.1.1
4526 * Copyright(c) 2006-2007, Ext JS, LLC.
4528 * Originally Released Under LGPL - original licence link has changed is not relivant.
4531 * <script type="text/javascript">
4535 * @class Roo.Template
4536 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4537 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4540 var t = new Roo.Template({
4541 html : '<div name="{id}">' +
4542 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4544 myformat: function (value, allValues) {
4545 return 'XX' + value;
4548 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4550 * For more information see this blog post with examples:
4551 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4552 - Create Elements using DOM, HTML fragments and Templates</a>.
4554 * @param {Object} cfg - Configuration object.
4556 Roo.Template = function(cfg){
4558 if(cfg instanceof Array){
4560 }else if(arguments.length > 1){
4561 cfg = Array.prototype.join.call(arguments, "");
4565 if (typeof(cfg) == 'object') {
4576 Roo.Template.prototype = {
4579 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4580 * it should be fixed so that template is observable...
4584 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4588 * Returns an HTML fragment of this template with the specified values applied.
4589 * @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'})
4590 * @return {String} The HTML fragment
4592 applyTemplate : function(values){
4596 return this.compiled(values);
4598 var useF = this.disableFormats !== true;
4599 var fm = Roo.util.Format, tpl = this;
4600 var fn = function(m, name, format, args){
4602 if(format.substr(0, 5) == "this."){
4603 return tpl.call(format.substr(5), values[name], values);
4606 // quoted values are required for strings in compiled templates,
4607 // but for non compiled we need to strip them
4608 // quoted reversed for jsmin
4609 var re = /^\s*['"](.*)["']\s*$/;
4610 args = args.split(',');
4611 for(var i = 0, len = args.length; i < len; i++){
4612 args[i] = args[i].replace(re, "$1");
4614 args = [values[name]].concat(args);
4616 args = [values[name]];
4618 return fm[format].apply(fm, args);
4621 return values[name] !== undefined ? values[name] : "";
4624 return this.html.replace(this.re, fn);
4642 this.loading = true;
4643 this.compiled = false;
4645 var cx = new Roo.data.Connection();
4649 success : function (response) {
4651 _t.html = response.responseText;
4655 failure : function(response) {
4656 Roo.log("Template failed to load from " + url);
4663 * Sets the HTML used as the template and optionally compiles it.
4664 * @param {String} html
4665 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4666 * @return {Roo.Template} this
4668 set : function(html, compile){
4670 this.compiled = null;
4678 * True to disable format functions (defaults to false)
4681 disableFormats : false,
4684 * The regular expression used to match template variables
4688 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4691 * Compiles the template into an internal function, eliminating the RegEx overhead.
4692 * @return {Roo.Template} this
4694 compile : function(){
4695 var fm = Roo.util.Format;
4696 var useF = this.disableFormats !== true;
4697 var sep = Roo.isGecko ? "+" : ",";
4698 var fn = function(m, name, format, args){
4700 args = args ? ',' + args : "";
4701 if(format.substr(0, 5) != "this."){
4702 format = "fm." + format + '(';
4704 format = 'this.call("'+ format.substr(5) + '", ';
4708 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4710 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4713 // branched to use + in gecko and [].join() in others
4715 body = "this.compiled = function(values){ return '" +
4716 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4719 body = ["this.compiled = function(values){ return ['"];
4720 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4721 body.push("'].join('');};");
4722 body = body.join('');
4732 // private function used to call members
4733 call : function(fnName, value, allValues){
4734 return this[fnName](value, allValues);
4738 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4739 * @param {String/HTMLElement/Roo.Element} el The context element
4740 * @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'})
4741 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4742 * @return {HTMLElement/Roo.Element} The new node or Element
4744 insertFirst: function(el, values, returnElement){
4745 return this.doInsert('afterBegin', el, values, returnElement);
4749 * Applies the supplied values to the template and inserts the new node(s) before el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @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'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertBefore: function(el, values, returnElement){
4756 return this.doInsert('beforeBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) after el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @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'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertAfter : function(el, values, returnElement){
4767 return this.doInsert('afterEnd', el, values, returnElement);
4771 * Applies the supplied values to the template and appends the new node(s) to el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @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'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 append : function(el, values, returnElement){
4778 return this.doInsert('beforeEnd', el, values, returnElement);
4781 doInsert : function(where, el, values, returnEl){
4782 el = Roo.getDom(el);
4783 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4784 return returnEl ? Roo.get(newNode, true) : newNode;
4788 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4789 * @param {String/HTMLElement/Roo.Element} el The context element
4790 * @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'})
4791 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4792 * @return {HTMLElement/Roo.Element} The new node or Element
4794 overwrite : function(el, values, returnElement){
4795 el = Roo.getDom(el);
4796 el.innerHTML = this.applyTemplate(values);
4797 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4801 * Alias for {@link #applyTemplate}
4804 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4807 Roo.DomHelper.Template = Roo.Template;
4810 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4811 * @param {String/HTMLElement} el A DOM element or its id
4812 * @returns {Roo.Template} The created template
4815 Roo.Template.from = function(el){
4816 el = Roo.getDom(el);
4817 return new Roo.Template(el.value || el.innerHTML);
4820 * Ext JS Library 1.1.1
4821 * Copyright(c) 2006-2007, Ext JS, LLC.
4823 * Originally Released Under LGPL - original licence link has changed is not relivant.
4826 * <script type="text/javascript">
4831 * This is code is also distributed under MIT license for use
4832 * with jQuery and prototype JavaScript libraries.
4835 * @class Roo.DomQuery
4836 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).
4838 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>
4841 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.
4843 <h4>Element Selectors:</h4>
4845 <li> <b>*</b> any element</li>
4846 <li> <b>E</b> an element with the tag E</li>
4847 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4848 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4849 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4850 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4852 <h4>Attribute Selectors:</h4>
4853 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4855 <li> <b>E[foo]</b> has an attribute "foo"</li>
4856 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4857 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4858 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4859 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4860 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4861 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4863 <h4>Pseudo Classes:</h4>
4865 <li> <b>E:first-child</b> E is the first child of its parent</li>
4866 <li> <b>E:last-child</b> E is the last child of its parent</li>
4867 <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>
4868 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4869 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4870 <li> <b>E:only-child</b> E is the only child of its parent</li>
4871 <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>
4872 <li> <b>E:first</b> the first E in the resultset</li>
4873 <li> <b>E:last</b> the last E in the resultset</li>
4874 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4875 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4876 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4877 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4878 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4879 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4880 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4881 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4882 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4884 <h4>CSS Value Selectors:</h4>
4886 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4887 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4888 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4889 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4890 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4891 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4895 Roo.DomQuery = function(){
4896 var cache = {}, simpleCache = {}, valueCache = {};
4897 var nonSpace = /\S/;
4898 var trimRe = /^\s+|\s+$/g;
4899 var tplRe = /\{(\d+)\}/g;
4900 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4901 var tagTokenRe = /^(#)?([\w-\*]+)/;
4902 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4904 function child(p, index){
4906 var n = p.firstChild;
4908 if(n.nodeType == 1){
4919 while((n = n.nextSibling) && n.nodeType != 1);
4924 while((n = n.previousSibling) && n.nodeType != 1);
4928 function children(d){
4929 var n = d.firstChild, ni = -1;
4931 var nx = n.nextSibling;
4932 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4942 function byClassName(c, a, v){
4946 var r = [], ri = -1, cn;
4947 for(var i = 0, ci; ci = c[i]; i++){
4948 if((' '+ci.className+' ').indexOf(v) != -1){
4955 function attrValue(n, attr){
4956 if(!n.tagName && typeof n.length != "undefined"){
4965 if(attr == "class" || attr == "className"){
4968 return n.getAttribute(attr) || n[attr];
4972 function getNodes(ns, mode, tagName){
4973 var result = [], ri = -1, cs;
4977 tagName = tagName || "*";
4978 if(typeof ns.getElementsByTagName != "undefined"){
4982 for(var i = 0, ni; ni = ns[i]; i++){
4983 cs = ni.getElementsByTagName(tagName);
4984 for(var j = 0, ci; ci = cs[j]; j++){
4988 }else if(mode == "/" || mode == ">"){
4989 var utag = tagName.toUpperCase();
4990 for(var i = 0, ni, cn; ni = ns[i]; i++){
4991 cn = ni.children || ni.childNodes;
4992 for(var j = 0, cj; cj = cn[j]; j++){
4993 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4998 }else if(mode == "+"){
4999 var utag = tagName.toUpperCase();
5000 for(var i = 0, n; n = ns[i]; i++){
5001 while((n = n.nextSibling) && n.nodeType != 1);
5002 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5006 }else if(mode == "~"){
5007 for(var i = 0, n; n = ns[i]; i++){
5008 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5017 function concat(a, b){
5021 for(var i = 0, l = b.length; i < l; i++){
5027 function byTag(cs, tagName){
5028 if(cs.tagName || cs == document){
5034 var r = [], ri = -1;
5035 tagName = tagName.toLowerCase();
5036 for(var i = 0, ci; ci = cs[i]; i++){
5037 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5044 function byId(cs, attr, id){
5045 if(cs.tagName || cs == document){
5051 var r = [], ri = -1;
5052 for(var i = 0,ci; ci = cs[i]; i++){
5053 if(ci && ci.id == id){
5061 function byAttribute(cs, attr, value, op, custom){
5062 var r = [], ri = -1, st = custom=="{";
5063 var f = Roo.DomQuery.operators[op];
5064 for(var i = 0, ci; ci = cs[i]; i++){
5067 a = Roo.DomQuery.getStyle(ci, attr);
5069 else if(attr == "class" || attr == "className"){
5071 }else if(attr == "for"){
5073 }else if(attr == "href"){
5074 a = ci.getAttribute("href", 2);
5076 a = ci.getAttribute(attr);
5078 if((f && f(a, value)) || (!f && a)){
5085 function byPseudo(cs, name, value){
5086 return Roo.DomQuery.pseudos[name](cs, value);
5089 // This is for IE MSXML which does not support expandos.
5090 // IE runs the same speed using setAttribute, however FF slows way down
5091 // and Safari completely fails so they need to continue to use expandos.
5092 var isIE = window.ActiveXObject ? true : false;
5094 // this eval is stop the compressor from
5095 // renaming the variable to something shorter
5097 /** eval:var:batch */
5102 function nodupIEXml(cs){
5104 cs[0].setAttribute("_nodup", d);
5106 for(var i = 1, len = cs.length; i < len; i++){
5108 if(!c.getAttribute("_nodup") != d){
5109 c.setAttribute("_nodup", d);
5113 for(var i = 0, len = cs.length; i < len; i++){
5114 cs[i].removeAttribute("_nodup");
5123 var len = cs.length, c, i, r = cs, cj, ri = -1;
5124 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5127 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5128 return nodupIEXml(cs);
5132 for(i = 1; c = cs[i]; i++){
5137 for(var j = 0; j < i; j++){
5140 for(j = i+1; cj = cs[j]; j++){
5152 function quickDiffIEXml(c1, c2){
5154 for(var i = 0, len = c1.length; i < len; i++){
5155 c1[i].setAttribute("_qdiff", d);
5158 for(var i = 0, len = c2.length; i < len; i++){
5159 if(c2[i].getAttribute("_qdiff") != d){
5160 r[r.length] = c2[i];
5163 for(var i = 0, len = c1.length; i < len; i++){
5164 c1[i].removeAttribute("_qdiff");
5169 function quickDiff(c1, c2){
5170 var len1 = c1.length;
5174 if(isIE && c1[0].selectSingleNode){
5175 return quickDiffIEXml(c1, c2);
5178 for(var i = 0; i < len1; i++){
5182 for(var i = 0, len = c2.length; i < len; i++){
5183 if(c2[i]._qdiff != d){
5184 r[r.length] = c2[i];
5190 function quickId(ns, mode, root, id){
5192 var d = root.ownerDocument || root;
5193 return d.getElementById(id);
5195 ns = getNodes(ns, mode, "*");
5196 return byId(ns, null, id);
5200 getStyle : function(el, name){
5201 return Roo.fly(el).getStyle(name);
5204 * Compiles a selector/xpath query into a reusable function. The returned function
5205 * takes one parameter "root" (optional), which is the context node from where the query should start.
5206 * @param {String} selector The selector/xpath query
5207 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5208 * @return {Function}
5210 compile : function(path, type){
5211 type = type || "select";
5213 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5214 var q = path, mode, lq;
5215 var tk = Roo.DomQuery.matchers;
5216 var tklen = tk.length;
5219 // accept leading mode switch
5220 var lmode = q.match(modeRe);
5221 if(lmode && lmode[1]){
5222 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5223 q = q.replace(lmode[1], "");
5225 // strip leading slashes
5226 while(path.substr(0, 1)=="/"){
5227 path = path.substr(1);
5230 while(q && lq != q){
5232 var tm = q.match(tagTokenRe);
5233 if(type == "select"){
5236 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5238 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5240 q = q.replace(tm[0], "");
5241 }else if(q.substr(0, 1) != '@'){
5242 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5247 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5254 while(!(mm = q.match(modeRe))){
5255 var matched = false;
5256 for(var j = 0; j < tklen; j++){
5258 var m = q.match(t.re);
5260 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5263 q = q.replace(m[0], "");
5268 // prevent infinite loop on bad selector
5270 throw 'Error parsing selector, parsing failed at "' + q + '"';
5274 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5275 q = q.replace(mm[1], "");
5278 fn[fn.length] = "return nodup(n);\n}";
5281 * list of variables that need from compression as they are used by eval.
5291 * eval:var:byClassName
5293 * eval:var:byAttribute
5294 * eval:var:attrValue
5302 * Selects a group of elements.
5303 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5304 * @param {Node} root (optional) The start of the query (defaults to document).
5307 select : function(path, root, type){
5308 if(!root || root == document){
5311 if(typeof root == "string"){
5312 root = document.getElementById(root);
5314 var paths = path.split(",");
5316 for(var i = 0, len = paths.length; i < len; i++){
5317 var p = paths[i].replace(trimRe, "");
5319 cache[p] = Roo.DomQuery.compile(p);
5321 throw p + " is not a valid selector";
5324 var result = cache[p](root);
5325 if(result && result != document){
5326 results = results.concat(result);
5329 if(paths.length > 1){
5330 return nodup(results);
5336 * Selects a single element.
5337 * @param {String} selector The selector/xpath query
5338 * @param {Node} root (optional) The start of the query (defaults to document).
5341 selectNode : function(path, root){
5342 return Roo.DomQuery.select(path, root)[0];
5346 * Selects the value of a node, optionally replacing null with the defaultValue.
5347 * @param {String} selector The selector/xpath query
5348 * @param {Node} root (optional) The start of the query (defaults to document).
5349 * @param {String} defaultValue
5351 selectValue : function(path, root, defaultValue){
5352 path = path.replace(trimRe, "");
5353 if(!valueCache[path]){
5354 valueCache[path] = Roo.DomQuery.compile(path, "select");
5356 var n = valueCache[path](root);
5357 n = n[0] ? n[0] : n;
5358 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5359 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5363 * Selects the value of a node, parsing integers and floats.
5364 * @param {String} selector The selector/xpath query
5365 * @param {Node} root (optional) The start of the query (defaults to document).
5366 * @param {Number} defaultValue
5369 selectNumber : function(path, root, defaultValue){
5370 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5371 return parseFloat(v);
5375 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5376 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5377 * @param {String} selector The simple selector to test
5380 is : function(el, ss){
5381 if(typeof el == "string"){
5382 el = document.getElementById(el);
5384 var isArray = (el instanceof Array);
5385 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5386 return isArray ? (result.length == el.length) : (result.length > 0);
5390 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5391 * @param {Array} el An array of elements to filter
5392 * @param {String} selector The simple selector to test
5393 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5394 * the selector instead of the ones that match
5397 filter : function(els, ss, nonMatches){
5398 ss = ss.replace(trimRe, "");
5399 if(!simpleCache[ss]){
5400 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5402 var result = simpleCache[ss](els);
5403 return nonMatches ? quickDiff(result, els) : result;
5407 * Collection of matching regular expressions and code snippets.
5411 select: 'n = byClassName(n, null, " {1} ");'
5413 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5414 select: 'n = byPseudo(n, "{1}", "{2}");'
5416 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5417 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5420 select: 'n = byId(n, null, "{1}");'
5423 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5428 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5429 * 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, > <.
5432 "=" : function(a, v){
5435 "!=" : function(a, v){
5438 "^=" : function(a, v){
5439 return a && a.substr(0, v.length) == v;
5441 "$=" : function(a, v){
5442 return a && a.substr(a.length-v.length) == v;
5444 "*=" : function(a, v){
5445 return a && a.indexOf(v) !== -1;
5447 "%=" : function(a, v){
5448 return (a % v) == 0;
5450 "|=" : function(a, v){
5451 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5453 "~=" : function(a, v){
5454 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5459 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5460 * and the argument (if any) supplied in the selector.
5463 "first-child" : function(c){
5464 var r = [], ri = -1, n;
5465 for(var i = 0, ci; ci = n = c[i]; i++){
5466 while((n = n.previousSibling) && n.nodeType != 1);
5474 "last-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.nextSibling) && n.nodeType != 1);
5485 "nth-child" : function(c, a) {
5486 var r = [], ri = -1;
5487 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5488 var f = (m[1] || 1) - 0, l = m[2] - 0;
5489 for(var i = 0, n; n = c[i]; i++){
5490 var pn = n.parentNode;
5491 if (batch != pn._batch) {
5493 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5494 if(cn.nodeType == 1){
5501 if (l == 0 || n.nodeIndex == l){
5504 } else if ((n.nodeIndex + l) % f == 0){
5512 "only-child" : function(c){
5513 var r = [], ri = -1;;
5514 for(var i = 0, ci; ci = c[i]; i++){
5515 if(!prev(ci) && !next(ci)){
5522 "empty" : function(c){
5523 var r = [], ri = -1;
5524 for(var i = 0, ci; ci = c[i]; i++){
5525 var cns = ci.childNodes, j = 0, cn, empty = true;
5528 if(cn.nodeType == 1 || cn.nodeType == 3){
5540 "contains" : function(c, v){
5541 var r = [], ri = -1;
5542 for(var i = 0, ci; ci = c[i]; i++){
5543 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5550 "nodeValue" : function(c, v){
5551 var r = [], ri = -1;
5552 for(var i = 0, ci; ci = c[i]; i++){
5553 if(ci.firstChild && ci.firstChild.nodeValue == v){
5560 "checked" : function(c){
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5563 if(ci.checked == true){
5570 "not" : function(c, ss){
5571 return Roo.DomQuery.filter(c, ss, true);
5574 "odd" : function(c){
5575 return this["nth-child"](c, "odd");
5578 "even" : function(c){
5579 return this["nth-child"](c, "even");
5582 "nth" : function(c, a){
5583 return c[a-1] || [];
5586 "first" : function(c){
5590 "last" : function(c){
5591 return c[c.length-1] || [];
5594 "has" : function(c, ss){
5595 var s = Roo.DomQuery.select;
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(s(ss, ci).length > 0){
5605 "next" : function(c, ss){
5606 var is = Roo.DomQuery.is;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5617 "prev" : function(c, ss){
5618 var is = Roo.DomQuery.is;
5619 var r = [], ri = -1;
5620 for(var i = 0, ci; ci = c[i]; i++){
5633 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5634 * @param {String} path The selector/xpath query
5635 * @param {Node} root (optional) The start of the query (defaults to document).
5640 Roo.query = Roo.DomQuery.select;
5643 * Ext JS Library 1.1.1
5644 * Copyright(c) 2006-2007, Ext JS, LLC.
5646 * Originally Released Under LGPL - original licence link has changed is not relivant.
5649 * <script type="text/javascript">
5653 * @class Roo.util.Observable
5654 * Base class that provides a common interface for publishing events. Subclasses are expected to
5655 * to have a property "events" with all the events defined.<br>
5658 Employee = function(name){
5665 Roo.extend(Employee, Roo.util.Observable);
5667 * @param {Object} config properties to use (incuding events / listeners)
5670 Roo.util.Observable = function(cfg){
5673 this.addEvents(cfg.events || {});
5675 delete cfg.events; // make sure
5678 Roo.apply(this, cfg);
5681 this.on(this.listeners);
5682 delete this.listeners;
5685 Roo.util.Observable.prototype = {
5687 * @cfg {Object} listeners list of events and functions to call for this object,
5691 'click' : function(e) {
5701 * Fires the specified event with the passed parameters (minus the event name).
5702 * @param {String} eventName
5703 * @param {Object...} args Variable number of parameters are passed to handlers
5704 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5706 fireEvent : function(){
5707 var ce = this.events[arguments[0].toLowerCase()];
5708 if(typeof ce == "object"){
5709 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5716 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5719 * Appends an event handler to this component
5720 * @param {String} eventName The type of event to listen for
5721 * @param {Function} handler The method the event invokes
5722 * @param {Object} scope (optional) The scope in which to execute the handler
5723 * function. The handler function's "this" context.
5724 * @param {Object} options (optional) An object containing handler configuration
5725 * properties. This may contain any of the following properties:<ul>
5726 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5727 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5728 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5729 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5730 * by the specified number of milliseconds. If the event fires again within that time, the original
5731 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5734 * <b>Combining Options</b><br>
5735 * Using the options argument, it is possible to combine different types of listeners:<br>
5737 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5739 el.on('click', this.onClick, this, {
5746 * <b>Attaching multiple handlers in 1 call</b><br>
5747 * The method also allows for a single argument to be passed which is a config object containing properties
5748 * which specify multiple handlers.
5757 fn: this.onMouseOver,
5761 fn: this.onMouseOut,
5767 * Or a shorthand syntax which passes the same scope object to all handlers:
5770 'click': this.onClick,
5771 'mouseover': this.onMouseOver,
5772 'mouseout': this.onMouseOut,
5777 addListener : function(eventName, fn, scope, o){
5778 if(typeof eventName == "object"){
5781 if(this.filterOptRe.test(e)){
5784 if(typeof o[e] == "function"){
5786 this.addListener(e, o[e], o.scope, o);
5788 // individual options
5789 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5794 o = (!o || typeof o == "boolean") ? {} : o;
5795 eventName = eventName.toLowerCase();
5796 var ce = this.events[eventName] || true;
5797 if(typeof ce == "boolean"){
5798 ce = new Roo.util.Event(this, eventName);
5799 this.events[eventName] = ce;
5801 ce.addListener(fn, scope, o);
5805 * Removes a listener
5806 * @param {String} eventName The type of event to listen for
5807 * @param {Function} handler The handler to remove
5808 * @param {Object} scope (optional) The scope (this object) for the handler
5810 removeListener : function(eventName, fn, scope){
5811 var ce = this.events[eventName.toLowerCase()];
5812 if(typeof ce == "object"){
5813 ce.removeListener(fn, scope);
5818 * Removes all listeners for this object
5820 purgeListeners : function(){
5821 for(var evt in this.events){
5822 if(typeof this.events[evt] == "object"){
5823 this.events[evt].clearListeners();
5828 relayEvents : function(o, events){
5829 var createHandler = function(ename){
5831 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5834 for(var i = 0, len = events.length; i < len; i++){
5835 var ename = events[i];
5836 if(!this.events[ename]){ this.events[ename] = true; };
5837 o.on(ename, createHandler(ename), this);
5842 * Used to define events on this Observable
5843 * @param {Object} object The object with the events defined
5845 addEvents : function(o){
5849 Roo.applyIf(this.events, o);
5853 * Checks to see if this object has any listeners for a specified event
5854 * @param {String} eventName The name of the event to check for
5855 * @return {Boolean} True if the event is being listened for, else false
5857 hasListener : function(eventName){
5858 var e = this.events[eventName];
5859 return typeof e == "object" && e.listeners.length > 0;
5863 * Appends an event handler to this element (shorthand for addListener)
5864 * @param {String} eventName The type of event to listen for
5865 * @param {Function} handler The method the event invokes
5866 * @param {Object} scope (optional) The scope in which to execute the handler
5867 * function. The handler function's "this" context.
5868 * @param {Object} options (optional)
5871 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5873 * Removes a listener (shorthand for removeListener)
5874 * @param {String} eventName The type of event to listen for
5875 * @param {Function} handler The handler to remove
5876 * @param {Object} scope (optional) The scope (this object) for the handler
5879 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5882 * Starts capture on the specified Observable. All events will be passed
5883 * to the supplied function with the event name + standard signature of the event
5884 * <b>before</b> the event is fired. If the supplied function returns false,
5885 * the event will not fire.
5886 * @param {Observable} o The Observable to capture
5887 * @param {Function} fn The function to call
5888 * @param {Object} scope (optional) The scope (this object) for the fn
5891 Roo.util.Observable.capture = function(o, fn, scope){
5892 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5896 * Removes <b>all</b> added captures from the Observable.
5897 * @param {Observable} o The Observable to release
5900 Roo.util.Observable.releaseCapture = function(o){
5901 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5906 var createBuffered = function(h, o, scope){
5907 var task = new Roo.util.DelayedTask();
5909 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5913 var createSingle = function(h, e, fn, scope){
5915 e.removeListener(fn, scope);
5916 return h.apply(scope, arguments);
5920 var createDelayed = function(h, o, scope){
5922 var args = Array.prototype.slice.call(arguments, 0);
5923 setTimeout(function(){
5924 h.apply(scope, args);
5929 Roo.util.Event = function(obj, name){
5932 this.listeners = [];
5935 Roo.util.Event.prototype = {
5936 addListener : function(fn, scope, options){
5937 var o = options || {};
5938 scope = scope || this.obj;
5939 if(!this.isListening(fn, scope)){
5940 var l = {fn: fn, scope: scope, options: o};
5943 h = createDelayed(h, o, scope);
5946 h = createSingle(h, this, fn, scope);
5949 h = createBuffered(h, o, scope);
5952 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5953 this.listeners.push(l);
5955 this.listeners = this.listeners.slice(0);
5956 this.listeners.push(l);
5961 findListener : function(fn, scope){
5962 scope = scope || this.obj;
5963 var ls = this.listeners;
5964 for(var i = 0, len = ls.length; i < len; i++){
5966 if(l.fn == fn && l.scope == scope){
5973 isListening : function(fn, scope){
5974 return this.findListener(fn, scope) != -1;
5977 removeListener : function(fn, scope){
5979 if((index = this.findListener(fn, scope)) != -1){
5981 this.listeners.splice(index, 1);
5983 this.listeners = this.listeners.slice(0);
5984 this.listeners.splice(index, 1);
5991 clearListeners : function(){
5992 this.listeners = [];
5996 var ls = this.listeners, scope, len = ls.length;
5999 var args = Array.prototype.slice.call(arguments, 0);
6000 for(var i = 0; i < len; i++){
6002 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6003 this.firing = false;
6007 this.firing = false;
6014 * Ext JS Library 1.1.1
6015 * Copyright(c) 2006-2007, Ext JS, LLC.
6017 * Originally Released Under LGPL - original licence link has changed is not relivant.
6020 * <script type="text/javascript">
6024 * @class Roo.EventManager
6025 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6026 * several useful events directly.
6027 * See {@link Roo.EventObject} for more details on normalized event objects.
6030 Roo.EventManager = function(){
6031 var docReadyEvent, docReadyProcId, docReadyState = false;
6032 var resizeEvent, resizeTask, textEvent, textSize;
6033 var E = Roo.lib.Event;
6034 var D = Roo.lib.Dom;
6037 var fireDocReady = function(){
6039 docReadyState = true;
6042 clearInterval(docReadyProcId);
6044 if(Roo.isGecko || Roo.isOpera) {
6045 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6048 var defer = document.getElementById("ie-deferred-loader");
6050 defer.onreadystatechange = null;
6051 defer.parentNode.removeChild(defer);
6055 docReadyEvent.fire();
6056 docReadyEvent.clearListeners();
6061 var initDocReady = function(){
6062 docReadyEvent = new Roo.util.Event();
6063 if(Roo.isGecko || Roo.isOpera) {
6064 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6066 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6067 var defer = document.getElementById("ie-deferred-loader");
6068 defer.onreadystatechange = function(){
6069 if(this.readyState == "complete"){
6073 }else if(Roo.isSafari){
6074 docReadyProcId = setInterval(function(){
6075 var rs = document.readyState;
6076 if(rs == "complete") {
6081 // no matter what, make sure it fires on load
6082 E.on(window, "load", fireDocReady);
6085 var createBuffered = function(h, o){
6086 var task = new Roo.util.DelayedTask(h);
6088 // create new event object impl so new events don't wipe out properties
6089 e = new Roo.EventObjectImpl(e);
6090 task.delay(o.buffer, h, null, [e]);
6094 var createSingle = function(h, el, ename, fn){
6096 Roo.EventManager.removeListener(el, ename, fn);
6101 var createDelayed = function(h, o){
6103 // create new event object impl so new events don't wipe out properties
6104 e = new Roo.EventObjectImpl(e);
6105 setTimeout(function(){
6111 var listen = function(element, ename, opt, fn, scope){
6112 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6113 fn = fn || o.fn; scope = scope || o.scope;
6114 var el = Roo.getDom(element);
6116 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6118 var h = function(e){
6119 e = Roo.EventObject.setEvent(e);
6122 t = e.getTarget(o.delegate, el);
6129 if(o.stopEvent === true){
6132 if(o.preventDefault === true){
6135 if(o.stopPropagation === true){
6136 e.stopPropagation();
6139 if(o.normalized === false){
6143 fn.call(scope || el, e, t, o);
6146 h = createDelayed(h, o);
6149 h = createSingle(h, el, ename, fn);
6152 h = createBuffered(h, o);
6154 fn._handlers = fn._handlers || [];
6155 fn._handlers.push([Roo.id(el), ename, h]);
6158 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6159 el.addEventListener("DOMMouseScroll", h, false);
6160 E.on(window, 'unload', function(){
6161 el.removeEventListener("DOMMouseScroll", h, false);
6164 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6165 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6170 var stopListening = function(el, ename, fn){
6171 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6173 for(var i = 0, len = hds.length; i < len; i++){
6175 if(h[0] == id && h[1] == ename){
6182 E.un(el, ename, hd);
6183 el = Roo.getDom(el);
6184 if(ename == "mousewheel" && el.addEventListener){
6185 el.removeEventListener("DOMMouseScroll", hd, false);
6187 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6188 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6192 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6199 * @scope Roo.EventManager
6204 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6205 * object with a Roo.EventObject
6206 * @param {Function} fn The method the event invokes
6207 * @param {Object} scope An object that becomes the scope of the handler
6208 * @param {boolean} override If true, the obj passed in becomes
6209 * the execution scope of the listener
6210 * @return {Function} The wrapped function
6213 wrap : function(fn, scope, override){
6215 Roo.EventObject.setEvent(e);
6216 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6221 * Appends an event handler to an element (shorthand for addListener)
6222 * @param {String/HTMLElement} element The html element or id to assign the
6223 * @param {String} eventName The type of event to listen for
6224 * @param {Function} handler The method the event invokes
6225 * @param {Object} scope (optional) The scope in which to execute the handler
6226 * function. The handler function's "this" context.
6227 * @param {Object} options (optional) An object containing handler configuration
6228 * properties. This may contain any of the following properties:<ul>
6229 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6230 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6231 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6232 * <li>preventDefault {Boolean} True to prevent the default action</li>
6233 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6234 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6235 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6236 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6237 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6238 * by the specified number of milliseconds. If the event fires again within that time, the original
6239 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6242 * <b>Combining Options</b><br>
6243 * Using the options argument, it is possible to combine different types of listeners:<br>
6245 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6247 el.on('click', this.onClick, this, {
6254 * <b>Attaching multiple handlers in 1 call</b><br>
6255 * The method also allows for a single argument to be passed which is a config object containing properties
6256 * which specify multiple handlers.
6266 fn: this.onMouseOver
6275 * Or a shorthand syntax:<br>
6278 'click' : this.onClick,
6279 'mouseover' : this.onMouseOver,
6280 'mouseout' : this.onMouseOut
6284 addListener : function(element, eventName, fn, scope, options){
6285 if(typeof eventName == "object"){
6291 if(typeof o[e] == "function"){
6293 listen(element, e, o, o[e], o.scope);
6295 // individual options
6296 listen(element, e, o[e]);
6301 return listen(element, eventName, options, fn, scope);
6305 * Removes an event handler
6307 * @param {String/HTMLElement} element The id or html element to remove the
6309 * @param {String} eventName The type of event
6310 * @param {Function} fn
6311 * @return {Boolean} True if a listener was actually removed
6313 removeListener : function(element, eventName, fn){
6314 return stopListening(element, eventName, fn);
6318 * Fires when the document is ready (before onload and before images are loaded). Can be
6319 * accessed shorthanded Roo.onReady().
6320 * @param {Function} fn The method the event invokes
6321 * @param {Object} scope An object that becomes the scope of the handler
6322 * @param {boolean} options
6324 onDocumentReady : function(fn, scope, options){
6325 if(docReadyState){ // if it already fired
6326 docReadyEvent.addListener(fn, scope, options);
6327 docReadyEvent.fire();
6328 docReadyEvent.clearListeners();
6334 docReadyEvent.addListener(fn, scope, options);
6338 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6339 * @param {Function} fn The method the event invokes
6340 * @param {Object} scope An object that becomes the scope of the handler
6341 * @param {boolean} options
6343 onWindowResize : function(fn, scope, options){
6345 resizeEvent = new Roo.util.Event();
6346 resizeTask = new Roo.util.DelayedTask(function(){
6347 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6349 E.on(window, "resize", function(){
6351 resizeTask.delay(50);
6353 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6357 resizeEvent.addListener(fn, scope, options);
6361 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6362 * @param {Function} fn The method the event invokes
6363 * @param {Object} scope An object that becomes the scope of the handler
6364 * @param {boolean} options
6366 onTextResize : function(fn, scope, options){
6368 textEvent = new Roo.util.Event();
6369 var textEl = new Roo.Element(document.createElement('div'));
6370 textEl.dom.className = 'x-text-resize';
6371 textEl.dom.innerHTML = 'X';
6372 textEl.appendTo(document.body);
6373 textSize = textEl.dom.offsetHeight;
6374 setInterval(function(){
6375 if(textEl.dom.offsetHeight != textSize){
6376 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6378 }, this.textResizeInterval);
6380 textEvent.addListener(fn, scope, options);
6384 * Removes the passed window resize listener.
6385 * @param {Function} fn The method the event invokes
6386 * @param {Object} scope The scope of handler
6388 removeResizeListener : function(fn, scope){
6390 resizeEvent.removeListener(fn, scope);
6395 fireResize : function(){
6397 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6401 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6405 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6407 textResizeInterval : 50
6412 * @scopeAlias pub=Roo.EventManager
6416 * Appends an event handler to an element (shorthand for addListener)
6417 * @param {String/HTMLElement} element The html element or id to assign the
6418 * @param {String} eventName The type of event to listen for
6419 * @param {Function} handler The method the event invokes
6420 * @param {Object} scope (optional) The scope in which to execute the handler
6421 * function. The handler function's "this" context.
6422 * @param {Object} options (optional) An object containing handler configuration
6423 * properties. This may contain any of the following properties:<ul>
6424 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6425 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6426 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6427 * <li>preventDefault {Boolean} True to prevent the default action</li>
6428 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6429 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6430 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6431 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6432 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6433 * by the specified number of milliseconds. If the event fires again within that time, the original
6434 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6437 * <b>Combining Options</b><br>
6438 * Using the options argument, it is possible to combine different types of listeners:<br>
6440 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6442 el.on('click', this.onClick, this, {
6449 * <b>Attaching multiple handlers in 1 call</b><br>
6450 * The method also allows for a single argument to be passed which is a config object containing properties
6451 * which specify multiple handlers.
6461 fn: this.onMouseOver
6470 * Or a shorthand syntax:<br>
6473 'click' : this.onClick,
6474 'mouseover' : this.onMouseOver,
6475 'mouseout' : this.onMouseOut
6479 pub.on = pub.addListener;
6480 pub.un = pub.removeListener;
6482 pub.stoppedMouseDownEvent = new Roo.util.Event();
6486 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6487 * @param {Function} fn The method the event invokes
6488 * @param {Object} scope An object that becomes the scope of the handler
6489 * @param {boolean} override If true, the obj passed in becomes
6490 * the execution scope of the listener
6494 Roo.onReady = Roo.EventManager.onDocumentReady;
6496 Roo.onReady(function(){
6497 var bd = Roo.get(document.body);
6502 : Roo.isGecko ? "roo-gecko"
6503 : Roo.isOpera ? "roo-opera"
6504 : Roo.isSafari ? "roo-safari" : ""];
6507 cls.push("roo-mac");
6510 cls.push("roo-linux");
6512 if(Roo.isBorderBox){
6513 cls.push('roo-border-box');
6515 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6516 var p = bd.dom.parentNode;
6518 p.className += ' roo-strict';
6521 bd.addClass(cls.join(' '));
6525 * @class Roo.EventObject
6526 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6527 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6530 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6532 var target = e.getTarget();
6535 var myDiv = Roo.get("myDiv");
6536 myDiv.on("click", handleClick);
6538 Roo.EventManager.on("myDiv", 'click', handleClick);
6539 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6543 Roo.EventObject = function(){
6545 var E = Roo.lib.Event;
6547 // safari keypress events for special keys return bad keycodes
6550 63235 : 39, // right
6553 63276 : 33, // page up
6554 63277 : 34, // page down
6555 63272 : 46, // delete
6560 // normalize button clicks
6561 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6562 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6564 Roo.EventObjectImpl = function(e){
6566 this.setEvent(e.browserEvent || e);
6569 Roo.EventObjectImpl.prototype = {
6571 * Used to fix doc tools.
6572 * @scope Roo.EventObject.prototype
6578 /** The normal browser event */
6579 browserEvent : null,
6580 /** The button pressed in a mouse event */
6582 /** True if the shift key was down during the event */
6584 /** True if the control key was down during the event */
6586 /** True if the alt key was down during the event */
6645 setEvent : function(e){
6646 if(e == this || (e && e.browserEvent)){ // already wrapped
6649 this.browserEvent = e;
6651 // normalize buttons
6652 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6653 if(e.type == 'click' && this.button == -1){
6657 this.shiftKey = e.shiftKey;
6658 // mac metaKey behaves like ctrlKey
6659 this.ctrlKey = e.ctrlKey || e.metaKey;
6660 this.altKey = e.altKey;
6661 // in getKey these will be normalized for the mac
6662 this.keyCode = e.keyCode;
6663 // keyup warnings on firefox.
6664 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6665 // cache the target for the delayed and or buffered events
6666 this.target = E.getTarget(e);
6668 this.xy = E.getXY(e);
6671 this.shiftKey = false;
6672 this.ctrlKey = false;
6673 this.altKey = false;
6683 * Stop the event (preventDefault and stopPropagation)
6685 stopEvent : function(){
6686 if(this.browserEvent){
6687 if(this.browserEvent.type == 'mousedown'){
6688 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6690 E.stopEvent(this.browserEvent);
6695 * Prevents the browsers default handling of the event.
6697 preventDefault : function(){
6698 if(this.browserEvent){
6699 E.preventDefault(this.browserEvent);
6704 isNavKeyPress : function(){
6705 var k = this.keyCode;
6706 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6707 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6710 isSpecialKey : function(){
6711 var k = this.keyCode;
6712 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6713 (k == 16) || (k == 17) ||
6714 (k >= 18 && k <= 20) ||
6715 (k >= 33 && k <= 35) ||
6716 (k >= 36 && k <= 39) ||
6717 (k >= 44 && k <= 45);
6720 * Cancels bubbling of the event.
6722 stopPropagation : function(){
6723 if(this.browserEvent){
6724 if(this.type == 'mousedown'){
6725 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6727 E.stopPropagation(this.browserEvent);
6732 * Gets the key code for the event.
6735 getCharCode : function(){
6736 return this.charCode || this.keyCode;
6740 * Returns a normalized keyCode for the event.
6741 * @return {Number} The key code
6743 getKey : function(){
6744 var k = this.keyCode || this.charCode;
6745 return Roo.isSafari ? (safariKeys[k] || k) : k;
6749 * Gets the x coordinate of the event.
6752 getPageX : function(){
6757 * Gets the y coordinate of the event.
6760 getPageY : function(){
6765 * Gets the time of the event.
6768 getTime : function(){
6769 if(this.browserEvent){
6770 return E.getTime(this.browserEvent);
6776 * Gets the page coordinates of the event.
6777 * @return {Array} The xy values like [x, y]
6784 * Gets the target for the event.
6785 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6786 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6787 search as a number or element (defaults to 10 || document.body)
6788 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6789 * @return {HTMLelement}
6791 getTarget : function(selector, maxDepth, returnEl){
6792 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6795 * Gets the related target.
6796 * @return {HTMLElement}
6798 getRelatedTarget : function(){
6799 if(this.browserEvent){
6800 return E.getRelatedTarget(this.browserEvent);
6806 * Normalizes mouse wheel delta across browsers
6807 * @return {Number} The delta
6809 getWheelDelta : function(){
6810 var e = this.browserEvent;
6812 if(e.wheelDelta){ /* IE/Opera. */
6813 delta = e.wheelDelta/120;
6814 }else if(e.detail){ /* Mozilla case. */
6815 delta = -e.detail/3;
6821 * Returns true if the control, meta, shift or alt key was pressed during this event.
6824 hasModifier : function(){
6825 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6829 * Returns true if the target of this event equals el or is a child of el
6830 * @param {String/HTMLElement/Element} el
6831 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6834 within : function(el, related){
6835 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6836 return t && Roo.fly(el).contains(t);
6839 getPoint : function(){
6840 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6844 return new Roo.EventObjectImpl();
6849 * Ext JS Library 1.1.1
6850 * Copyright(c) 2006-2007, Ext JS, LLC.
6852 * Originally Released Under LGPL - original licence link has changed is not relivant.
6855 * <script type="text/javascript">
6859 // was in Composite Element!??!?!
6862 var D = Roo.lib.Dom;
6863 var E = Roo.lib.Event;
6864 var A = Roo.lib.Anim;
6866 // local style camelizing for speed
6868 var camelRe = /(-[a-z])/gi;
6869 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6870 var view = document.defaultView;
6873 * @class Roo.Element
6874 * Represents an Element in the DOM.<br><br>
6877 var el = Roo.get("my-div");
6880 var el = getEl("my-div");
6882 // or with a DOM element
6883 var el = Roo.get(myDivElement);
6885 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6886 * each call instead of constructing a new one.<br><br>
6887 * <b>Animations</b><br />
6888 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6889 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6891 Option Default Description
6892 --------- -------- ---------------------------------------------
6893 duration .35 The duration of the animation in seconds
6894 easing easeOut The YUI easing method
6895 callback none A function to execute when the anim completes
6896 scope this The scope (this) of the callback function
6898 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6899 * manipulate the animation. Here's an example:
6901 var el = Roo.get("my-div");
6906 // default animation
6907 el.setWidth(100, true);
6909 // animation with some options set
6916 // using the "anim" property to get the Anim object
6922 el.setWidth(100, opt);
6924 if(opt.anim.isAnimated()){
6928 * <b> Composite (Collections of) Elements</b><br />
6929 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6930 * @constructor Create a new Element directly.
6931 * @param {String/HTMLElement} element
6932 * @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).
6934 Roo.Element = function(element, forceNew){
6935 var dom = typeof element == "string" ?
6936 document.getElementById(element) : element;
6937 if(!dom){ // invalid id/element
6941 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6942 return Roo.Element.cache[id];
6952 * The DOM element ID
6955 this.id = id || Roo.id(dom);
6958 var El = Roo.Element;
6962 * The element's default display mode (defaults to "")
6965 originalDisplay : "",
6969 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6974 * Sets the element's visibility mode. When setVisible() is called it
6975 * will use this to determine whether to set the visibility or the display property.
6976 * @param visMode Element.VISIBILITY or Element.DISPLAY
6977 * @return {Roo.Element} this
6979 setVisibilityMode : function(visMode){
6980 this.visibilityMode = visMode;
6984 * Convenience method for setVisibilityMode(Element.DISPLAY)
6985 * @param {String} display (optional) What to set display to when visible
6986 * @return {Roo.Element} this
6988 enableDisplayMode : function(display){
6989 this.setVisibilityMode(El.DISPLAY);
6990 if(typeof display != "undefined") this.originalDisplay = display;
6995 * 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)
6996 * @param {String} selector The simple selector to test
6997 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6998 search as a number or element (defaults to 10 || document.body)
6999 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7000 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7002 findParent : function(simpleSelector, maxDepth, returnEl){
7003 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7004 maxDepth = maxDepth || 50;
7005 if(typeof maxDepth != "number"){
7006 stopEl = Roo.getDom(maxDepth);
7009 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7010 if(dq.is(p, simpleSelector)){
7011 return returnEl ? Roo.get(p) : p;
7021 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7022 * @param {String} selector The simple selector to test
7023 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7024 search as a number or element (defaults to 10 || document.body)
7025 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7026 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7028 findParentNode : function(simpleSelector, maxDepth, returnEl){
7029 var p = Roo.fly(this.dom.parentNode, '_internal');
7030 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7034 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7035 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7036 * @param {String} selector The simple selector to test
7037 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7038 search as a number or element (defaults to 10 || document.body)
7039 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7041 up : function(simpleSelector, maxDepth){
7042 return this.findParentNode(simpleSelector, maxDepth, true);
7048 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7049 * @param {String} selector The simple selector to test
7050 * @return {Boolean} True if this element matches the selector, else false
7052 is : function(simpleSelector){
7053 return Roo.DomQuery.is(this.dom, simpleSelector);
7057 * Perform animation on this element.
7058 * @param {Object} args The YUI animation control args
7059 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7060 * @param {Function} onComplete (optional) Function to call when animation completes
7061 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7062 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7063 * @return {Roo.Element} this
7065 animate : function(args, duration, onComplete, easing, animType){
7066 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7071 * @private Internal animation call
7073 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7074 animType = animType || 'run';
7076 var anim = Roo.lib.Anim[animType](
7078 (opt.duration || defaultDur) || .35,
7079 (opt.easing || defaultEase) || 'easeOut',
7081 Roo.callback(cb, this);
7082 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7090 // private legacy anim prep
7091 preanim : function(a, i){
7092 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7096 * Removes worthless text nodes
7097 * @param {Boolean} forceReclean (optional) By default the element
7098 * keeps track if it has been cleaned already so
7099 * you can call this over and over. However, if you update the element and
7100 * need to force a reclean, you can pass true.
7102 clean : function(forceReclean){
7103 if(this.isCleaned && forceReclean !== true){
7107 var d = this.dom, n = d.firstChild, ni = -1;
7109 var nx = n.nextSibling;
7110 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7117 this.isCleaned = true;
7122 calcOffsetsTo : function(el){
7125 var restorePos = false;
7126 if(el.getStyle('position') == 'static'){
7127 el.position('relative');
7132 while(op && op != d && op.tagName != 'HTML'){
7135 op = op.offsetParent;
7138 el.position('static');
7144 * Scrolls this element into view within the passed container.
7145 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7146 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7147 * @return {Roo.Element} this
7149 scrollIntoView : function(container, hscroll){
7150 var c = Roo.getDom(container) || document.body;
7153 var o = this.calcOffsetsTo(c),
7156 b = t+el.offsetHeight,
7157 r = l+el.offsetWidth;
7159 var ch = c.clientHeight;
7160 var ct = parseInt(c.scrollTop, 10);
7161 var cl = parseInt(c.scrollLeft, 10);
7163 var cr = cl + c.clientWidth;
7171 if(hscroll !== false){
7175 c.scrollLeft = r-c.clientWidth;
7182 scrollChildIntoView : function(child, hscroll){
7183 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7187 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7188 * the new height may not be available immediately.
7189 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7190 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7191 * @param {Function} onComplete (optional) Function to call when animation completes
7192 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7193 * @return {Roo.Element} this
7195 autoHeight : function(animate, duration, onComplete, easing){
7196 var oldHeight = this.getHeight();
7198 this.setHeight(1); // force clipping
7199 setTimeout(function(){
7200 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7202 this.setHeight(height);
7204 if(typeof onComplete == "function"){
7208 this.setHeight(oldHeight); // restore original height
7209 this.setHeight(height, animate, duration, function(){
7211 if(typeof onComplete == "function") onComplete();
7212 }.createDelegate(this), easing);
7214 }.createDelegate(this), 0);
7219 * Returns true if this element is an ancestor of the passed element
7220 * @param {HTMLElement/String} el The element to check
7221 * @return {Boolean} True if this element is an ancestor of el, else false
7223 contains : function(el){
7224 if(!el){return false;}
7225 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7229 * Checks whether the element is currently visible using both visibility and display properties.
7230 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7231 * @return {Boolean} True if the element is currently visible, else false
7233 isVisible : function(deep) {
7234 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7235 if(deep !== true || !vis){
7238 var p = this.dom.parentNode;
7239 while(p && p.tagName.toLowerCase() != "body"){
7240 if(!Roo.fly(p, '_isVisible').isVisible()){
7249 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7250 * @param {String} selector The CSS selector
7251 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7252 * @return {CompositeElement/CompositeElementLite} The composite element
7254 select : function(selector, unique){
7255 return El.select(selector, unique, this.dom);
7259 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7260 * @param {String} selector The CSS selector
7261 * @return {Array} An array of the matched nodes
7263 query : function(selector, unique){
7264 return Roo.DomQuery.select(selector, this.dom);
7268 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7269 * @param {String} selector The CSS selector
7270 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7271 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7273 child : function(selector, returnDom){
7274 var n = Roo.DomQuery.selectNode(selector, this.dom);
7275 return returnDom ? n : Roo.get(n);
7279 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 down : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7291 * @param {String} group The group the DD object is member of
7292 * @param {Object} config The DD config object
7293 * @param {Object} overrides An object containing methods to override/implement on the DD object
7294 * @return {Roo.dd.DD} The DD object
7296 initDD : function(group, config, overrides){
7297 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7298 return Roo.apply(dd, overrides);
7302 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7303 * @param {String} group The group the DDProxy object is member of
7304 * @param {Object} config The DDProxy config object
7305 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7306 * @return {Roo.dd.DDProxy} The DDProxy object
7308 initDDProxy : function(group, config, overrides){
7309 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7310 return Roo.apply(dd, overrides);
7314 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7315 * @param {String} group The group the DDTarget object is member of
7316 * @param {Object} config The DDTarget config object
7317 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7318 * @return {Roo.dd.DDTarget} The DDTarget object
7320 initDDTarget : function(group, config, overrides){
7321 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7322 return Roo.apply(dd, overrides);
7326 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7327 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7328 * @param {Boolean} visible Whether the element is visible
7329 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7330 * @return {Roo.Element} this
7332 setVisible : function(visible, animate){
7334 if(this.visibilityMode == El.DISPLAY){
7335 this.setDisplayed(visible);
7338 this.dom.style.visibility = visible ? "visible" : "hidden";
7341 // closure for composites
7343 var visMode = this.visibilityMode;
7345 this.setOpacity(.01);
7346 this.setVisible(true);
7348 this.anim({opacity: { to: (visible?1:0) }},
7349 this.preanim(arguments, 1),
7350 null, .35, 'easeIn', function(){
7352 if(visMode == El.DISPLAY){
7353 dom.style.display = "none";
7355 dom.style.visibility = "hidden";
7357 Roo.get(dom).setOpacity(1);
7365 * Returns true if display is not "none"
7368 isDisplayed : function() {
7369 return this.getStyle("display") != "none";
7373 * Toggles the element's visibility or display, depending on visibility mode.
7374 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7375 * @return {Roo.Element} this
7377 toggle : function(animate){
7378 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7383 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7384 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7385 * @return {Roo.Element} this
7387 setDisplayed : function(value) {
7388 if(typeof value == "boolean"){
7389 value = value ? this.originalDisplay : "none";
7391 this.setStyle("display", value);
7396 * Tries to focus the element. Any exceptions are caught and ignored.
7397 * @return {Roo.Element} this
7399 focus : function() {
7407 * Tries to blur the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7418 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7419 * @param {String/Array} className The CSS class to add, or an array of classes
7420 * @return {Roo.Element} this
7422 addClass : function(className){
7423 if(className instanceof Array){
7424 for(var i = 0, len = className.length; i < len; i++) {
7425 this.addClass(className[i]);
7428 if(className && !this.hasClass(className)){
7429 this.dom.className = this.dom.className + " " + className;
7436 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7437 * @param {String/Array} className The CSS class to add, or an array of classes
7438 * @return {Roo.Element} this
7440 radioClass : function(className){
7441 var siblings = this.dom.parentNode.childNodes;
7442 for(var i = 0; i < siblings.length; i++) {
7443 var s = siblings[i];
7444 if(s.nodeType == 1){
7445 Roo.get(s).removeClass(className);
7448 this.addClass(className);
7453 * Removes one or more CSS classes from the element.
7454 * @param {String/Array} className The CSS class to remove, or an array of classes
7455 * @return {Roo.Element} this
7457 removeClass : function(className){
7458 if(!className || !this.dom.className){
7461 if(className instanceof Array){
7462 for(var i = 0, len = className.length; i < len; i++) {
7463 this.removeClass(className[i]);
7466 if(this.hasClass(className)){
7467 var re = this.classReCache[className];
7469 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7470 this.classReCache[className] = re;
7472 this.dom.className =
7473 this.dom.className.replace(re, " ");
7483 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7484 * @param {String} className The CSS class to toggle
7485 * @return {Roo.Element} this
7487 toggleClass : function(className){
7488 if(this.hasClass(className)){
7489 this.removeClass(className);
7491 this.addClass(className);
7497 * Checks if the specified CSS class exists on this element's DOM node.
7498 * @param {String} className The CSS class to check for
7499 * @return {Boolean} True if the class exists, else false
7501 hasClass : function(className){
7502 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7506 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7507 * @param {String} oldClassName The CSS class to replace
7508 * @param {String} newClassName The replacement CSS class
7509 * @return {Roo.Element} this
7511 replaceClass : function(oldClassName, newClassName){
7512 this.removeClass(oldClassName);
7513 this.addClass(newClassName);
7518 * Returns an object with properties matching the styles requested.
7519 * For example, el.getStyles('color', 'font-size', 'width') might return
7520 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7521 * @param {String} style1 A style name
7522 * @param {String} style2 A style name
7523 * @param {String} etc.
7524 * @return {Object} The style object
7526 getStyles : function(){
7527 var a = arguments, len = a.length, r = {};
7528 for(var i = 0; i < len; i++){
7529 r[a[i]] = this.getStyle(a[i]);
7535 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7536 * @param {String} property The style property whose value is returned.
7537 * @return {String} The current value of the style property for this element.
7539 getStyle : function(){
7540 return view && view.getComputedStyle ?
7542 var el = this.dom, v, cs, camel;
7543 if(prop == 'float'){
7546 if(el.style && (v = el.style[prop])){
7549 if(cs = view.getComputedStyle(el, "")){
7550 if(!(camel = propCache[prop])){
7551 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7558 var el = this.dom, v, cs, camel;
7559 if(prop == 'opacity'){
7560 if(typeof el.style.filter == 'string'){
7561 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7563 var fv = parseFloat(m[1]);
7565 return fv ? fv / 100 : 0;
7570 }else if(prop == 'float'){
7571 prop = "styleFloat";
7573 if(!(camel = propCache[prop])){
7574 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7576 if(v = el.style[camel]){
7579 if(cs = el.currentStyle){
7587 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7588 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7589 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7590 * @return {Roo.Element} this
7592 setStyle : function(prop, value){
7593 if(typeof prop == "string"){
7595 if (prop == 'float') {
7596 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7601 if(!(camel = propCache[prop])){
7602 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7605 if(camel == 'opacity') {
7606 this.setOpacity(value);
7608 this.dom.style[camel] = value;
7611 for(var style in prop){
7612 if(typeof prop[style] != "function"){
7613 this.setStyle(style, prop[style]);
7621 * More flexible version of {@link #setStyle} for setting style properties.
7622 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7623 * a function which returns such a specification.
7624 * @return {Roo.Element} this
7626 applyStyles : function(style){
7627 Roo.DomHelper.applyStyles(this.dom, style);
7632 * 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).
7633 * @return {Number} The X position of the element
7636 return D.getX(this.dom);
7640 * 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).
7641 * @return {Number} The Y position of the element
7644 return D.getY(this.dom);
7648 * 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).
7649 * @return {Array} The XY position of the element
7652 return D.getXY(this.dom);
7656 * 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).
7657 * @param {Number} The X position of the element
7658 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7659 * @return {Roo.Element} this
7661 setX : function(x, animate){
7663 D.setX(this.dom, x);
7665 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7671 * 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).
7672 * @param {Number} The Y position of the element
7673 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7674 * @return {Roo.Element} this
7676 setY : function(y, animate){
7678 D.setY(this.dom, y);
7680 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7686 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7687 * @param {String} left The left CSS property value
7688 * @return {Roo.Element} this
7690 setLeft : function(left){
7691 this.setStyle("left", this.addUnits(left));
7696 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7697 * @param {String} top The top CSS property value
7698 * @return {Roo.Element} this
7700 setTop : function(top){
7701 this.setStyle("top", this.addUnits(top));
7706 * Sets the element's CSS right style.
7707 * @param {String} right The right CSS property value
7708 * @return {Roo.Element} this
7710 setRight : function(right){
7711 this.setStyle("right", this.addUnits(right));
7716 * Sets the element's CSS bottom style.
7717 * @param {String} bottom The bottom CSS property value
7718 * @return {Roo.Element} this
7720 setBottom : function(bottom){
7721 this.setStyle("bottom", this.addUnits(bottom));
7726 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7727 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7728 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7729 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7730 * @return {Roo.Element} this
7732 setXY : function(pos, animate){
7734 D.setXY(this.dom, pos);
7736 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7742 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7743 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7744 * @param {Number} x X value for new position (coordinates are page-based)
7745 * @param {Number} y Y value for new position (coordinates are page-based)
7746 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747 * @return {Roo.Element} this
7749 setLocation : function(x, y, animate){
7750 this.setXY([x, y], this.preanim(arguments, 2));
7755 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7756 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7757 * @param {Number} x X value for new position (coordinates are page-based)
7758 * @param {Number} y Y value for new position (coordinates are page-based)
7759 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7760 * @return {Roo.Element} this
7762 moveTo : function(x, y, animate){
7763 this.setXY([x, y], this.preanim(arguments, 2));
7768 * Returns the region of the given element.
7769 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7770 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7772 getRegion : function(){
7773 return D.getRegion(this.dom);
7777 * Returns the offset height of the element
7778 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7779 * @return {Number} The element's height
7781 getHeight : function(contentHeight){
7782 var h = this.dom.offsetHeight || 0;
7783 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7787 * Returns the offset width of the element
7788 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7789 * @return {Number} The element's width
7791 getWidth : function(contentWidth){
7792 var w = this.dom.offsetWidth || 0;
7793 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7797 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7798 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7799 * if a height has not been set using CSS.
7802 getComputedHeight : function(){
7803 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7805 h = parseInt(this.getStyle('height'), 10) || 0;
7806 if(!this.isBorderBox()){
7807 h += this.getFrameWidth('tb');
7814 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7815 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7816 * if a width has not been set using CSS.
7819 getComputedWidth : function(){
7820 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7822 w = parseInt(this.getStyle('width'), 10) || 0;
7823 if(!this.isBorderBox()){
7824 w += this.getFrameWidth('lr');
7831 * Returns the size of the element.
7832 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7833 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7835 getSize : function(contentSize){
7836 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7840 * Returns the width and height of the viewport.
7841 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7843 getViewSize : function(){
7844 var d = this.dom, doc = document, aw = 0, ah = 0;
7845 if(d == doc || d == doc.body){
7846 return {width : D.getViewWidth(), height: D.getViewHeight()};
7849 width : d.clientWidth,
7850 height: d.clientHeight
7856 * Returns the value of the "value" attribute
7857 * @param {Boolean} asNumber true to parse the value as a number
7858 * @return {String/Number}
7860 getValue : function(asNumber){
7861 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7865 adjustWidth : function(width){
7866 if(typeof width == "number"){
7867 if(this.autoBoxAdjust && !this.isBorderBox()){
7868 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7878 adjustHeight : function(height){
7879 if(typeof height == "number"){
7880 if(this.autoBoxAdjust && !this.isBorderBox()){
7881 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7891 * Set the width of the element
7892 * @param {Number} width The new width
7893 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7894 * @return {Roo.Element} this
7896 setWidth : function(width, animate){
7897 width = this.adjustWidth(width);
7899 this.dom.style.width = this.addUnits(width);
7901 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7907 * Set the height of the element
7908 * @param {Number} height The new height
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setHeight : function(height, animate){
7913 height = this.adjustHeight(height);
7915 this.dom.style.height = this.addUnits(height);
7917 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7923 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7924 * @param {Number} width The new width
7925 * @param {Number} height The new height
7926 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7927 * @return {Roo.Element} this
7929 setSize : function(width, height, animate){
7930 if(typeof width == "object"){ // in case of object from getSize()
7931 height = width.height; width = width.width;
7933 width = this.adjustWidth(width); height = this.adjustHeight(height);
7935 this.dom.style.width = this.addUnits(width);
7936 this.dom.style.height = this.addUnits(height);
7938 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7944 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7945 * @param {Number} x X value for new position (coordinates are page-based)
7946 * @param {Number} y Y value for new position (coordinates are page-based)
7947 * @param {Number} width The new width
7948 * @param {Number} height The new height
7949 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7950 * @return {Roo.Element} this
7952 setBounds : function(x, y, width, height, animate){
7954 this.setSize(width, height);
7955 this.setLocation(x, y);
7957 width = this.adjustWidth(width); height = this.adjustHeight(height);
7958 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7959 this.preanim(arguments, 4), 'motion');
7965 * 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.
7966 * @param {Roo.lib.Region} region The region to fill
7967 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7968 * @return {Roo.Element} this
7970 setRegion : function(region, animate){
7971 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7976 * Appends an event handler
7978 * @param {String} eventName The type of event to append
7979 * @param {Function} fn The method the event invokes
7980 * @param {Object} scope (optional) The scope (this object) of the fn
7981 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7983 addListener : function(eventName, fn, scope, options){
7985 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7990 * Removes an event handler from this element
7991 * @param {String} eventName the type of event to remove
7992 * @param {Function} fn the method the event invokes
7993 * @return {Roo.Element} this
7995 removeListener : function(eventName, fn){
7996 Roo.EventManager.removeListener(this.dom, eventName, fn);
8001 * Removes all previous added listeners from this element
8002 * @return {Roo.Element} this
8004 removeAllListeners : function(){
8005 E.purgeElement(this.dom);
8009 relayEvent : function(eventName, observable){
8010 this.on(eventName, function(e){
8011 observable.fireEvent(eventName, e);
8016 * Set the opacity of the element
8017 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8018 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8019 * @return {Roo.Element} this
8021 setOpacity : function(opacity, animate){
8023 var s = this.dom.style;
8026 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8027 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8029 s.opacity = opacity;
8032 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8038 * Gets the left X coordinate
8039 * @param {Boolean} local True to get the local css position instead of page coordinate
8042 getLeft : function(local){
8046 return parseInt(this.getStyle("left"), 10) || 0;
8051 * Gets the right X coordinate of the element (element X position + element width)
8052 * @param {Boolean} local True to get the local css position instead of page coordinate
8055 getRight : function(local){
8057 return this.getX() + this.getWidth();
8059 return (this.getLeft(true) + this.getWidth()) || 0;
8064 * Gets the top Y coordinate
8065 * @param {Boolean} local True to get the local css position instead of page coordinate
8068 getTop : function(local) {
8072 return parseInt(this.getStyle("top"), 10) || 0;
8077 * Gets the bottom Y coordinate of the element (element Y position + element height)
8078 * @param {Boolean} local True to get the local css position instead of page coordinate
8081 getBottom : function(local){
8083 return this.getY() + this.getHeight();
8085 return (this.getTop(true) + this.getHeight()) || 0;
8090 * Initializes positioning on this element. If a desired position is not passed, it will make the
8091 * the element positioned relative IF it is not already positioned.
8092 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8093 * @param {Number} zIndex (optional) The zIndex to apply
8094 * @param {Number} x (optional) Set the page X position
8095 * @param {Number} y (optional) Set the page Y position
8097 position : function(pos, zIndex, x, y){
8099 if(this.getStyle('position') == 'static'){
8100 this.setStyle('position', 'relative');
8103 this.setStyle("position", pos);
8106 this.setStyle("z-index", zIndex);
8108 if(x !== undefined && y !== undefined){
8110 }else if(x !== undefined){
8112 }else if(y !== undefined){
8118 * Clear positioning back to the default when the document was loaded
8119 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8120 * @return {Roo.Element} this
8122 clearPositioning : function(value){
8130 "position" : "static"
8136 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8137 * snapshot before performing an update and then restoring the element.
8140 getPositioning : function(){
8141 var l = this.getStyle("left");
8142 var t = this.getStyle("top");
8144 "position" : this.getStyle("position"),
8146 "right" : l ? "" : this.getStyle("right"),
8148 "bottom" : t ? "" : this.getStyle("bottom"),
8149 "z-index" : this.getStyle("z-index")
8154 * Gets the width of the border(s) for the specified side(s)
8155 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8156 * passing lr would get the border (l)eft width + the border (r)ight width.
8157 * @return {Number} The width of the sides passed added together
8159 getBorderWidth : function(side){
8160 return this.addStyles(side, El.borders);
8164 * Gets the width of the padding(s) for the specified side(s)
8165 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8166 * passing lr would get the padding (l)eft + the padding (r)ight.
8167 * @return {Number} The padding of the sides passed added together
8169 getPadding : function(side){
8170 return this.addStyles(side, El.paddings);
8174 * Set positioning with an object returned by getPositioning().
8175 * @param {Object} posCfg
8176 * @return {Roo.Element} this
8178 setPositioning : function(pc){
8179 this.applyStyles(pc);
8180 if(pc.right == "auto"){
8181 this.dom.style.right = "";
8183 if(pc.bottom == "auto"){
8184 this.dom.style.bottom = "";
8190 fixDisplay : function(){
8191 if(this.getStyle("display") == "none"){
8192 this.setStyle("visibility", "hidden");
8193 this.setStyle("display", this.originalDisplay); // first try reverting to default
8194 if(this.getStyle("display") == "none"){ // if that fails, default to block
8195 this.setStyle("display", "block");
8201 * Quick set left and top adding default units
8202 * @param {String} left The left CSS property value
8203 * @param {String} top The top CSS property value
8204 * @return {Roo.Element} this
8206 setLeftTop : function(left, top){
8207 this.dom.style.left = this.addUnits(left);
8208 this.dom.style.top = this.addUnits(top);
8213 * Move this element relative to its current position.
8214 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8215 * @param {Number} distance How far to move the element in pixels
8216 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8217 * @return {Roo.Element} this
8219 move : function(direction, distance, animate){
8220 var xy = this.getXY();
8221 direction = direction.toLowerCase();
8225 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8229 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8234 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8239 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8246 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8247 * @return {Roo.Element} this
8250 if(!this.isClipped){
8251 this.isClipped = true;
8252 this.originalClip = {
8253 "o": this.getStyle("overflow"),
8254 "x": this.getStyle("overflow-x"),
8255 "y": this.getStyle("overflow-y")
8257 this.setStyle("overflow", "hidden");
8258 this.setStyle("overflow-x", "hidden");
8259 this.setStyle("overflow-y", "hidden");
8265 * Return clipping (overflow) to original clipping before clip() was called
8266 * @return {Roo.Element} this
8268 unclip : function(){
8270 this.isClipped = false;
8271 var o = this.originalClip;
8272 if(o.o){this.setStyle("overflow", o.o);}
8273 if(o.x){this.setStyle("overflow-x", o.x);}
8274 if(o.y){this.setStyle("overflow-y", o.y);}
8281 * Gets the x,y coordinates specified by the anchor position on the element.
8282 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8283 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8284 * {width: (target width), height: (target height)} (defaults to the element's current size)
8285 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8286 * @return {Array} [x, y] An array containing the element's x and y coordinates
8288 getAnchorXY : function(anchor, local, s){
8289 //Passing a different size is useful for pre-calculating anchors,
8290 //especially for anchored animations that change the el size.
8292 var w, h, vp = false;
8295 if(d == document.body || d == document){
8297 w = D.getViewWidth(); h = D.getViewHeight();
8299 w = this.getWidth(); h = this.getHeight();
8302 w = s.width; h = s.height;
8304 var x = 0, y = 0, r = Math.round;
8305 switch((anchor || "tl").toLowerCase()){
8347 var sc = this.getScroll();
8348 return [x + sc.left, y + sc.top];
8350 //Add the element's offset xy
8351 var o = this.getXY();
8352 return [x+o[0], y+o[1]];
8356 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8357 * supported position values.
8358 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8359 * @param {String} position The position to align to.
8360 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8361 * @return {Array} [x, y]
8363 getAlignToXY : function(el, p, o){
8367 throw "Element.alignTo with an element that doesn't exist";
8369 var c = false; //constrain to viewport
8370 var p1 = "", p2 = "";
8377 }else if(p.indexOf("-") == -1){
8380 p = p.toLowerCase();
8381 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8383 throw "Element.alignTo with an invalid alignment " + p;
8385 p1 = m[1]; p2 = m[2]; c = !!m[3];
8387 //Subtract the aligned el's internal xy from the target's offset xy
8388 //plus custom offset to get the aligned el's new offset xy
8389 var a1 = this.getAnchorXY(p1, true);
8390 var a2 = el.getAnchorXY(p2, false);
8391 var x = a2[0] - a1[0] + o[0];
8392 var y = a2[1] - a1[1] + o[1];
8394 //constrain the aligned el to viewport if necessary
8395 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8396 // 5px of margin for ie
8397 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8399 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8400 //perpendicular to the vp border, allow the aligned el to slide on that border,
8401 //otherwise swap the aligned el to the opposite border of the target.
8402 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8403 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8404 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8405 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8408 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8409 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8411 if((x+w) > dw + scrollX){
8412 x = swapX ? r.left-w : dw+scrollX-w;
8415 x = swapX ? r.right : scrollX;
8417 if((y+h) > dh + scrollY){
8418 y = swapY ? r.top-h : dh+scrollY-h;
8421 y = swapY ? r.bottom : scrollY;
8428 getConstrainToXY : function(){
8429 var os = {top:0, left:0, bottom:0, right: 0};
8431 return function(el, local, offsets, proposedXY){
8433 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8435 var vw, vh, vx = 0, vy = 0;
8436 if(el.dom == document.body || el.dom == document){
8437 vw = Roo.lib.Dom.getViewWidth();
8438 vh = Roo.lib.Dom.getViewHeight();
8440 vw = el.dom.clientWidth;
8441 vh = el.dom.clientHeight;
8443 var vxy = el.getXY();
8449 var s = el.getScroll();
8451 vx += offsets.left + s.left;
8452 vy += offsets.top + s.top;
8454 vw -= offsets.right;
8455 vh -= offsets.bottom;
8460 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8461 var x = xy[0], y = xy[1];
8462 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8464 // only move it if it needs it
8467 // first validate right/bottom
8476 // then make sure top/left isn't negative
8485 return moved ? [x, y] : false;
8490 adjustForConstraints : function(xy, parent, offsets){
8491 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8495 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8496 * document it aligns it to the viewport.
8497 * The position parameter is optional, and can be specified in any one of the following formats:
8499 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8500 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8501 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8502 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8503 * <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
8504 * element's anchor point, and the second value is used as the target's anchor point.</li>
8506 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8507 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8508 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8509 * that specified in order to enforce the viewport constraints.
8510 * Following are all of the supported anchor positions:
8513 ----- -----------------------------
8514 tl The top left corner (default)
8515 t The center of the top edge
8516 tr The top right corner
8517 l The center of the left edge
8518 c In the center of the element
8519 r The center of the right edge
8520 bl The bottom left corner
8521 b The center of the bottom edge
8522 br The bottom right corner
8526 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8527 el.alignTo("other-el");
8529 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8530 el.alignTo("other-el", "tr?");
8532 // align the bottom right corner of el with the center left edge of other-el
8533 el.alignTo("other-el", "br-l?");
8535 // align the center of el with the bottom left corner of other-el and
8536 // adjust the x position by -6 pixels (and the y position by 0)
8537 el.alignTo("other-el", "c-bl", [-6, 0]);
8539 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8540 * @param {String} position The position to align to.
8541 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8542 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8543 * @return {Roo.Element} this
8545 alignTo : function(element, position, offsets, animate){
8546 var xy = this.getAlignToXY(element, position, offsets);
8547 this.setXY(xy, this.preanim(arguments, 3));
8552 * Anchors an element to another element and realigns it when the window is resized.
8553 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8554 * @param {String} position The position to align to.
8555 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8556 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8557 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8558 * is a number, it is used as the buffer delay (defaults to 50ms).
8559 * @param {Function} callback The function to call after the animation finishes
8560 * @return {Roo.Element} this
8562 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8563 var action = function(){
8564 this.alignTo(el, alignment, offsets, animate);
8565 Roo.callback(callback, this);
8567 Roo.EventManager.onWindowResize(action, this);
8568 var tm = typeof monitorScroll;
8569 if(tm != 'undefined'){
8570 Roo.EventManager.on(window, 'scroll', action, this,
8571 {buffer: tm == 'number' ? monitorScroll : 50});
8573 action.call(this); // align immediately
8577 * Clears any opacity settings from this element. Required in some cases for IE.
8578 * @return {Roo.Element} this
8580 clearOpacity : function(){
8581 if (window.ActiveXObject) {
8582 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8583 this.dom.style.filter = "";
8586 this.dom.style.opacity = "";
8587 this.dom.style["-moz-opacity"] = "";
8588 this.dom.style["-khtml-opacity"] = "";
8594 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8595 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8596 * @return {Roo.Element} this
8598 hide : function(animate){
8599 this.setVisible(false, this.preanim(arguments, 0));
8604 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8605 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8606 * @return {Roo.Element} this
8608 show : function(animate){
8609 this.setVisible(true, this.preanim(arguments, 0));
8614 * @private Test if size has a unit, otherwise appends the default
8616 addUnits : function(size){
8617 return Roo.Element.addUnits(size, this.defaultUnit);
8621 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8622 * @return {Roo.Element} this
8624 beginMeasure : function(){
8626 if(el.offsetWidth || el.offsetHeight){
8627 return this; // offsets work already
8630 var p = this.dom, b = document.body; // start with this element
8631 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8632 var pe = Roo.get(p);
8633 if(pe.getStyle('display') == 'none'){
8634 changed.push({el: p, visibility: pe.getStyle("visibility")});
8635 p.style.visibility = "hidden";
8636 p.style.display = "block";
8640 this._measureChanged = changed;
8646 * Restores displays to before beginMeasure was called
8647 * @return {Roo.Element} this
8649 endMeasure : function(){
8650 var changed = this._measureChanged;
8652 for(var i = 0, len = changed.length; i < len; i++) {
8654 r.el.style.visibility = r.visibility;
8655 r.el.style.display = "none";
8657 this._measureChanged = null;
8663 * Update the innerHTML of this element, optionally searching for and processing scripts
8664 * @param {String} html The new HTML
8665 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8666 * @param {Function} callback For async script loading you can be noticed when the update completes
8667 * @return {Roo.Element} this
8669 update : function(html, loadScripts, callback){
8670 if(typeof html == "undefined"){
8673 if(loadScripts !== true){
8674 this.dom.innerHTML = html;
8675 if(typeof callback == "function"){
8683 html += '<span id="' + id + '"></span>';
8685 E.onAvailable(id, function(){
8686 var hd = document.getElementsByTagName("head")[0];
8687 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8688 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8689 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8692 while(match = re.exec(html)){
8693 var attrs = match[1];
8694 var srcMatch = attrs ? attrs.match(srcRe) : false;
8695 if(srcMatch && srcMatch[2]){
8696 var s = document.createElement("script");
8697 s.src = srcMatch[2];
8698 var typeMatch = attrs.match(typeRe);
8699 if(typeMatch && typeMatch[2]){
8700 s.type = typeMatch[2];
8703 }else if(match[2] && match[2].length > 0){
8704 if(window.execScript) {
8705 window.execScript(match[2]);
8713 window.eval(match[2]);
8717 var el = document.getElementById(id);
8718 if(el){el.parentNode.removeChild(el);}
8719 if(typeof callback == "function"){
8723 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8728 * Direct access to the UpdateManager update() method (takes the same parameters).
8729 * @param {String/Function} url The url for this request or a function to call to get the url
8730 * @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}
8731 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8732 * @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.
8733 * @return {Roo.Element} this
8736 var um = this.getUpdateManager();
8737 um.update.apply(um, arguments);
8742 * Gets this element's UpdateManager
8743 * @return {Roo.UpdateManager} The UpdateManager
8745 getUpdateManager : function(){
8746 if(!this.updateManager){
8747 this.updateManager = new Roo.UpdateManager(this);
8749 return this.updateManager;
8753 * Disables text selection for this element (normalized across browsers)
8754 * @return {Roo.Element} this
8756 unselectable : function(){
8757 this.dom.unselectable = "on";
8758 this.swallowEvent("selectstart", true);
8759 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8760 this.addClass("x-unselectable");
8765 * Calculates the x, y to center this element on the screen
8766 * @return {Array} The x, y values [x, y]
8768 getCenterXY : function(){
8769 return this.getAlignToXY(document, 'c-c');
8773 * Centers the Element in either the viewport, or another Element.
8774 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8776 center : function(centerIn){
8777 this.alignTo(centerIn || document, 'c-c');
8782 * Tests various css rules/browsers to determine if this element uses a border box
8785 isBorderBox : function(){
8786 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8790 * Return a box {x, y, width, height} that can be used to set another elements
8791 * size/location to match this element.
8792 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8793 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8794 * @return {Object} box An object in the format {x, y, width, height}
8796 getBox : function(contentBox, local){
8801 var left = parseInt(this.getStyle("left"), 10) || 0;
8802 var top = parseInt(this.getStyle("top"), 10) || 0;
8805 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8807 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8809 var l = this.getBorderWidth("l")+this.getPadding("l");
8810 var r = this.getBorderWidth("r")+this.getPadding("r");
8811 var t = this.getBorderWidth("t")+this.getPadding("t");
8812 var b = this.getBorderWidth("b")+this.getPadding("b");
8813 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)};
8815 bx.right = bx.x + bx.width;
8816 bx.bottom = bx.y + bx.height;
8821 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8822 for more information about the sides.
8823 * @param {String} sides
8826 getFrameWidth : function(sides, onlyContentBox){
8827 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8831 * 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.
8832 * @param {Object} box The box to fill {x, y, width, height}
8833 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8834 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8835 * @return {Roo.Element} this
8837 setBox : function(box, adjust, animate){
8838 var w = box.width, h = box.height;
8839 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8840 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8841 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8843 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8848 * Forces the browser to repaint this element
8849 * @return {Roo.Element} this
8851 repaint : function(){
8853 this.addClass("x-repaint");
8854 setTimeout(function(){
8855 Roo.get(dom).removeClass("x-repaint");
8861 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8862 * then it returns the calculated width of the sides (see getPadding)
8863 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8864 * @return {Object/Number}
8866 getMargins : function(side){
8869 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8870 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8871 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8872 right: parseInt(this.getStyle("margin-right"), 10) || 0
8875 return this.addStyles(side, El.margins);
8880 addStyles : function(sides, styles){
8882 for(var i = 0, len = sides.length; i < len; i++){
8883 v = this.getStyle(styles[sides.charAt(i)]);
8885 w = parseInt(v, 10);
8893 * Creates a proxy element of this element
8894 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8895 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8896 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8897 * @return {Roo.Element} The new proxy element
8899 createProxy : function(config, renderTo, matchBox){
8901 renderTo = Roo.getDom(renderTo);
8903 renderTo = document.body;
8905 config = typeof config == "object" ?
8906 config : {tag : "div", cls: config};
8907 var proxy = Roo.DomHelper.append(renderTo, config, true);
8909 proxy.setBox(this.getBox());
8915 * Puts a mask over this element to disable user interaction. Requires core.css.
8916 * This method can only be applied to elements which accept child nodes.
8917 * @param {String} msg (optional) A message to display in the mask
8918 * @param {String} msgCls (optional) A css class to apply to the msg element
8919 * @return {Element} The mask element
8921 mask : function(msg, msgCls)
8923 if(this.getStyle("position") == "static"){
8924 this.setStyle("position", "relative");
8927 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8929 this.addClass("x-masked");
8930 this._mask.setDisplayed(true);
8935 while (dom && dom.style) {
8936 if (!isNaN(parseInt(dom.style.zIndex))) {
8937 z = Math.max(z, parseInt(dom.style.zIndex));
8939 dom = dom.parentNode;
8941 // if we are masking the body - then it hides everything..
8942 if (this.dom == document.body) {
8944 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8945 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8948 if(typeof msg == 'string'){
8950 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8952 var mm = this._maskMsg;
8953 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8954 mm.dom.firstChild.innerHTML = msg;
8955 mm.setDisplayed(true);
8957 mm.setStyle('z-index', z + 102);
8959 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8960 this._mask.setHeight(this.getHeight());
8962 this._mask.setStyle('z-index', z + 100);
8968 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8969 * it is cached for reuse.
8971 unmask : function(removeEl){
8973 if(removeEl === true){
8974 this._mask.remove();
8977 this._maskMsg.remove();
8978 delete this._maskMsg;
8981 this._mask.setDisplayed(false);
8983 this._maskMsg.setDisplayed(false);
8987 this.removeClass("x-masked");
8991 * Returns true if this element is masked
8994 isMasked : function(){
8995 return this._mask && this._mask.isVisible();
8999 * Creates an iframe shim for this element to keep selects and other windowed objects from
9001 * @return {Roo.Element} The new shim element
9003 createShim : function(){
9004 var el = document.createElement('iframe');
9005 el.frameBorder = 'no';
9006 el.className = 'roo-shim';
9007 if(Roo.isIE && Roo.isSecure){
9008 el.src = Roo.SSL_SECURE_URL;
9010 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9011 shim.autoBoxAdjust = false;
9016 * Removes this element from the DOM and deletes it from the cache
9018 remove : function(){
9019 if(this.dom.parentNode){
9020 this.dom.parentNode.removeChild(this.dom);
9022 delete El.cache[this.dom.id];
9026 * Sets up event handlers to add and remove a css class when the mouse is over this element
9027 * @param {String} className
9028 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9029 * mouseout events for children elements
9030 * @return {Roo.Element} this
9032 addClassOnOver : function(className, preventFlicker){
9033 this.on("mouseover", function(){
9034 Roo.fly(this, '_internal').addClass(className);
9036 var removeFn = function(e){
9037 if(preventFlicker !== true || !e.within(this, true)){
9038 Roo.fly(this, '_internal').removeClass(className);
9041 this.on("mouseout", removeFn, this.dom);
9046 * Sets up event handlers to add and remove a css class when this element has the focus
9047 * @param {String} className
9048 * @return {Roo.Element} this
9050 addClassOnFocus : function(className){
9051 this.on("focus", function(){
9052 Roo.fly(this, '_internal').addClass(className);
9054 this.on("blur", function(){
9055 Roo.fly(this, '_internal').removeClass(className);
9060 * 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)
9061 * @param {String} className
9062 * @return {Roo.Element} this
9064 addClassOnClick : function(className){
9066 this.on("mousedown", function(){
9067 Roo.fly(dom, '_internal').addClass(className);
9068 var d = Roo.get(document);
9069 var fn = function(){
9070 Roo.fly(dom, '_internal').removeClass(className);
9071 d.removeListener("mouseup", fn);
9073 d.on("mouseup", fn);
9079 * Stops the specified event from bubbling and optionally prevents the default action
9080 * @param {String} eventName
9081 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9082 * @return {Roo.Element} this
9084 swallowEvent : function(eventName, preventDefault){
9085 var fn = function(e){
9086 e.stopPropagation();
9091 if(eventName instanceof Array){
9092 for(var i = 0, len = eventName.length; i < len; i++){
9093 this.on(eventName[i], fn);
9097 this.on(eventName, fn);
9104 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9107 * Sizes this element to its parent element's dimensions performing
9108 * neccessary box adjustments.
9109 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9110 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9111 * @return {Roo.Element} this
9113 fitToParent : function(monitorResize, targetParent) {
9114 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9115 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9116 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9119 var p = Roo.get(targetParent || this.dom.parentNode);
9120 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9121 if (monitorResize === true) {
9122 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9123 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9129 * Gets the next sibling, skipping text nodes
9130 * @return {HTMLElement} The next sibling or null
9132 getNextSibling : function(){
9133 var n = this.dom.nextSibling;
9134 while(n && n.nodeType != 1){
9141 * Gets the previous sibling, skipping text nodes
9142 * @return {HTMLElement} The previous sibling or null
9144 getPrevSibling : function(){
9145 var n = this.dom.previousSibling;
9146 while(n && n.nodeType != 1){
9147 n = n.previousSibling;
9154 * Appends the passed element(s) to this element
9155 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9156 * @return {Roo.Element} this
9158 appendChild: function(el){
9165 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9166 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9167 * automatically generated with the specified attributes.
9168 * @param {HTMLElement} insertBefore (optional) a child element of this element
9169 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9170 * @return {Roo.Element} The new child element
9172 createChild: function(config, insertBefore, returnDom){
9173 config = config || {tag:'div'};
9175 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9177 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9181 * Appends this element to the passed element
9182 * @param {String/HTMLElement/Element} el The new parent element
9183 * @return {Roo.Element} this
9185 appendTo: function(el){
9186 el = Roo.getDom(el);
9187 el.appendChild(this.dom);
9192 * Inserts this element before the passed element in the DOM
9193 * @param {String/HTMLElement/Element} el The element to insert before
9194 * @return {Roo.Element} this
9196 insertBefore: function(el){
9197 el = Roo.getDom(el);
9198 el.parentNode.insertBefore(this.dom, el);
9203 * Inserts this element after the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert after
9205 * @return {Roo.Element} this
9207 insertAfter: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el.nextSibling);
9214 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9215 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9216 * @return {Roo.Element} The new child
9218 insertFirst: function(el, returnDom){
9220 if(typeof el == 'object' && !el.nodeType){ // dh config
9221 return this.createChild(el, this.dom.firstChild, returnDom);
9223 el = Roo.getDom(el);
9224 this.dom.insertBefore(el, this.dom.firstChild);
9225 return !returnDom ? Roo.get(el) : el;
9230 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9231 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9232 * @param {String} where (optional) 'before' or 'after' defaults to before
9233 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9234 * @return {Roo.Element} the inserted Element
9236 insertSibling: function(el, where, returnDom){
9237 where = where ? where.toLowerCase() : 'before';
9239 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9241 if(typeof el == 'object' && !el.nodeType){ // dh config
9242 if(where == 'after' && !this.dom.nextSibling){
9243 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9245 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9249 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9250 where == 'before' ? this.dom : this.dom.nextSibling);
9259 * Creates and wraps this element with another element
9260 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9261 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9262 * @return {HTMLElement/Element} The newly created wrapper element
9264 wrap: function(config, returnDom){
9266 config = {tag: "div"};
9268 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9269 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9274 * Replaces the passed element with this element
9275 * @param {String/HTMLElement/Element} el The element to replace
9276 * @return {Roo.Element} this
9278 replace: function(el){
9280 this.insertBefore(el);
9286 * Inserts an html fragment into this element
9287 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9288 * @param {String} html The HTML fragment
9289 * @param {Boolean} returnEl True to return an Roo.Element
9290 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9292 insertHtml : function(where, html, returnEl){
9293 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9294 return returnEl ? Roo.get(el) : el;
9298 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9299 * @param {Object} o The object with the attributes
9300 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9301 * @return {Roo.Element} this
9303 set : function(o, useSet){
9305 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9307 if(attr == "style" || typeof o[attr] == "function") continue;
9309 el.className = o["cls"];
9311 if(useSet) el.setAttribute(attr, o[attr]);
9312 else el[attr] = o[attr];
9316 Roo.DomHelper.applyStyles(el, o.style);
9322 * Convenience method for constructing a KeyMap
9323 * @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:
9324 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9325 * @param {Function} fn The function to call
9326 * @param {Object} scope (optional) The scope of the function
9327 * @return {Roo.KeyMap} The KeyMap created
9329 addKeyListener : function(key, fn, scope){
9331 if(typeof key != "object" || key instanceof Array){
9347 return new Roo.KeyMap(this, config);
9351 * Creates a KeyMap for this element
9352 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9353 * @return {Roo.KeyMap} The KeyMap created
9355 addKeyMap : function(config){
9356 return new Roo.KeyMap(this, config);
9360 * Returns true if this element is scrollable.
9363 isScrollable : function(){
9365 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9369 * 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().
9370 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9371 * @param {Number} value The new scroll value
9372 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9373 * @return {Element} this
9376 scrollTo : function(side, value, animate){
9377 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9379 this.dom[prop] = value;
9381 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9382 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9388 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9389 * within this element's scrollable range.
9390 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9391 * @param {Number} distance How far to scroll the element in pixels
9392 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9393 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9394 * was scrolled as far as it could go.
9396 scroll : function(direction, distance, animate){
9397 if(!this.isScrollable()){
9401 var l = el.scrollLeft, t = el.scrollTop;
9402 var w = el.scrollWidth, h = el.scrollHeight;
9403 var cw = el.clientWidth, ch = el.clientHeight;
9404 direction = direction.toLowerCase();
9405 var scrolled = false;
9406 var a = this.preanim(arguments, 2);
9411 var v = Math.min(l + distance, w-cw);
9412 this.scrollTo("left", v, a);
9419 var v = Math.max(l - distance, 0);
9420 this.scrollTo("left", v, a);
9428 var v = Math.max(t - distance, 0);
9429 this.scrollTo("top", v, a);
9437 var v = Math.min(t + distance, h-ch);
9438 this.scrollTo("top", v, a);
9447 * Translates the passed page coordinates into left/top css values for this element
9448 * @param {Number/Array} x The page x or an array containing [x, y]
9449 * @param {Number} y The page y
9450 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9452 translatePoints : function(x, y){
9453 if(typeof x == 'object' || x instanceof Array){
9456 var p = this.getStyle('position');
9457 var o = this.getXY();
9459 var l = parseInt(this.getStyle('left'), 10);
9460 var t = parseInt(this.getStyle('top'), 10);
9463 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9466 t = (p == "relative") ? 0 : this.dom.offsetTop;
9469 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9473 * Returns the current scroll position of the element.
9474 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9476 getScroll : function(){
9477 var d = this.dom, doc = document;
9478 if(d == doc || d == doc.body){
9479 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9480 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9481 return {left: l, top: t};
9483 return {left: d.scrollLeft, top: d.scrollTop};
9488 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9489 * are convert to standard 6 digit hex color.
9490 * @param {String} attr The css attribute
9491 * @param {String} defaultValue The default value to use when a valid color isn't found
9492 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9495 getColor : function(attr, defaultValue, prefix){
9496 var v = this.getStyle(attr);
9497 if(!v || v == "transparent" || v == "inherit") {
9498 return defaultValue;
9500 var color = typeof prefix == "undefined" ? "#" : prefix;
9501 if(v.substr(0, 4) == "rgb("){
9502 var rvs = v.slice(4, v.length -1).split(",");
9503 for(var i = 0; i < 3; i++){
9504 var h = parseInt(rvs[i]).toString(16);
9511 if(v.substr(0, 1) == "#"){
9513 for(var i = 1; i < 4; i++){
9514 var c = v.charAt(i);
9517 }else if(v.length == 7){
9518 color += v.substr(1);
9522 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9526 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9527 * gradient background, rounded corners and a 4-way shadow.
9528 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9529 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9530 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9531 * @return {Roo.Element} this
9533 boxWrap : function(cls){
9534 cls = cls || 'x-box';
9535 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9536 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9541 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9542 * @param {String} namespace The namespace in which to look for the attribute
9543 * @param {String} name The attribute name
9544 * @return {String} The attribute value
9546 getAttributeNS : Roo.isIE ? function(ns, name){
9548 var type = typeof d[ns+":"+name];
9549 if(type != 'undefined' && type != 'unknown'){
9550 return d[ns+":"+name];
9553 } : function(ns, name){
9555 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9559 var ep = El.prototype;
9562 * Appends an event handler (Shorthand for addListener)
9563 * @param {String} eventName The type of event to append
9564 * @param {Function} fn The method the event invokes
9565 * @param {Object} scope (optional) The scope (this object) of the fn
9566 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9569 ep.on = ep.addListener;
9571 ep.mon = ep.addListener;
9574 * Removes an event handler from this element (shorthand for removeListener)
9575 * @param {String} eventName the type of event to remove
9576 * @param {Function} fn the method the event invokes
9577 * @return {Roo.Element} this
9580 ep.un = ep.removeListener;
9583 * true to automatically adjust width and height settings for box-model issues (default to true)
9585 ep.autoBoxAdjust = true;
9588 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9591 El.addUnits = function(v, defaultUnit){
9592 if(v === "" || v == "auto"){
9595 if(v === undefined){
9598 if(typeof v == "number" || !El.unitPattern.test(v)){
9599 return v + (defaultUnit || 'px');
9604 // special markup used throughout Roo when box wrapping elements
9605 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>';
9607 * Visibility mode constant - Use visibility to hide element
9613 * Visibility mode constant - Use display to hide element
9619 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9620 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9621 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9633 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9634 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9635 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9636 * @return {Element} The Element object
9639 El.get = function(el){
9641 if(!el){ return null; }
9642 if(typeof el == "string"){ // element id
9643 if(!(elm = document.getElementById(el))){
9646 if(ex = El.cache[el]){
9649 ex = El.cache[el] = new El(elm);
9652 }else if(el.tagName){ // dom element
9656 if(ex = El.cache[id]){
9659 ex = El.cache[id] = new El(el);
9662 }else if(el instanceof El){
9664 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9665 // catch case where it hasn't been appended
9666 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9669 }else if(el.isComposite){
9671 }else if(el instanceof Array){
9672 return El.select(el);
9673 }else if(el == document){
9674 // create a bogus element object representing the document object
9676 var f = function(){};
9677 f.prototype = El.prototype;
9679 docEl.dom = document;
9687 El.uncache = function(el){
9688 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9690 delete El.cache[a[i].id || a[i]];
9696 // Garbage collection - uncache elements/purge listeners on orphaned elements
9697 // so we don't hold a reference and cause the browser to retain them
9698 El.garbageCollect = function(){
9699 if(!Roo.enableGarbageCollector){
9700 clearInterval(El.collectorThread);
9703 for(var eid in El.cache){
9704 var el = El.cache[eid], d = el.dom;
9705 // -------------------------------------------------------
9706 // Determining what is garbage:
9707 // -------------------------------------------------------
9709 // dom node is null, definitely garbage
9710 // -------------------------------------------------------
9712 // no parentNode == direct orphan, definitely garbage
9713 // -------------------------------------------------------
9714 // !d.offsetParent && !document.getElementById(eid)
9715 // display none elements have no offsetParent so we will
9716 // also try to look it up by it's id. However, check
9717 // offsetParent first so we don't do unneeded lookups.
9718 // This enables collection of elements that are not orphans
9719 // directly, but somewhere up the line they have an orphan
9721 // -------------------------------------------------------
9722 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9723 delete El.cache[eid];
9724 if(d && Roo.enableListenerCollection){
9730 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9734 El.Flyweight = function(dom){
9737 El.Flyweight.prototype = El.prototype;
9739 El._flyweights = {};
9741 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9742 * the dom node can be overwritten by other code.
9743 * @param {String/HTMLElement} el The dom node or id
9744 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9745 * prevent conflicts (e.g. internally Roo uses "_internal")
9747 * @return {Element} The shared Element object
9749 El.fly = function(el, named){
9750 named = named || '_global';
9751 el = Roo.getDom(el);
9755 if(!El._flyweights[named]){
9756 El._flyweights[named] = new El.Flyweight();
9758 El._flyweights[named].dom = el;
9759 return El._flyweights[named];
9763 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9764 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9765 * Shorthand of {@link Roo.Element#get}
9766 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9767 * @return {Element} The Element object
9773 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9774 * the dom node can be overwritten by other code.
9775 * Shorthand of {@link Roo.Element#fly}
9776 * @param {String/HTMLElement} el The dom node or id
9777 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9778 * prevent conflicts (e.g. internally Roo uses "_internal")
9780 * @return {Element} The shared Element object
9786 // speedy lookup for elements never to box adjust
9787 var noBoxAdjust = Roo.isStrict ? {
9790 input:1, select:1, textarea:1
9792 if(Roo.isIE || Roo.isGecko){
9793 noBoxAdjust['button'] = 1;
9797 Roo.EventManager.on(window, 'unload', function(){
9799 delete El._flyweights;
9807 Roo.Element.selectorFunction = Roo.DomQuery.select;
9810 Roo.Element.select = function(selector, unique, root){
9812 if(typeof selector == "string"){
9813 els = Roo.Element.selectorFunction(selector, root);
9814 }else if(selector.length !== undefined){
9817 throw "Invalid selector";
9819 if(unique === true){
9820 return new Roo.CompositeElement(els);
9822 return new Roo.CompositeElementLite(els);
9826 * Selects elements based on the passed CSS selector to enable working on them as 1.
9827 * @param {String/Array} selector The CSS selector or an array of elements
9828 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9829 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9830 * @return {CompositeElementLite/CompositeElement}
9834 Roo.select = Roo.Element.select;
9851 * Ext JS Library 1.1.1
9852 * Copyright(c) 2006-2007, Ext JS, LLC.
9854 * Originally Released Under LGPL - original licence link has changed is not relivant.
9857 * <script type="text/javascript">
9862 //Notifies Element that fx methods are available
9863 Roo.enableFx = true;
9867 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9868 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9869 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9870 * Element effects to work.</p><br/>
9872 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9873 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9874 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9875 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9876 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9877 * expected results and should be done with care.</p><br/>
9879 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9880 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9883 ----- -----------------------------
9884 tl The top left corner
9885 t The center of the top edge
9886 tr The top right corner
9887 l The center of the left edge
9888 r The center of the right edge
9889 bl The bottom left corner
9890 b The center of the bottom edge
9891 br The bottom right corner
9893 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9894 * below are common options that can be passed to any Fx method.</b>
9895 * @cfg {Function} callback A function called when the effect is finished
9896 * @cfg {Object} scope The scope of the effect function
9897 * @cfg {String} easing A valid Easing value for the effect
9898 * @cfg {String} afterCls A css class to apply after the effect
9899 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9900 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9901 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9902 * effects that end with the element being visually hidden, ignored otherwise)
9903 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9904 * a function which returns such a specification that will be applied to the Element after the effect finishes
9905 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9906 * @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
9907 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9911 * Slides the element into view. An anchor point can be optionally passed to set the point of
9912 * origin for the slide effect. This function automatically handles wrapping the element with
9913 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9916 // default: slide the element in from the top
9919 // custom: slide the element in from the right with a 2-second duration
9920 el.slideIn('r', { duration: 2 });
9922 // common config options shown with default values
9928 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9929 * @param {Object} options (optional) Object literal with any of the Fx config options
9930 * @return {Roo.Element} The Element
9932 slideIn : function(anchor, o){
9933 var el = this.getFxEl();
9936 el.queueFx(o, function(){
9938 anchor = anchor || "t";
9940 // fix display to visibility
9943 // restore values after effect
9944 var r = this.getFxRestore();
9945 var b = this.getBox();
9946 // fixed size for slide
9950 var wrap = this.fxWrap(r.pos, o, "hidden");
9952 var st = this.dom.style;
9953 st.visibility = "visible";
9954 st.position = "absolute";
9956 // clear out temp styles after slide and unwrap
9957 var after = function(){
9958 el.fxUnwrap(wrap, r.pos, o);
9960 st.height = r.height;
9963 // time to calc the positions
9964 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9966 switch(anchor.toLowerCase()){
9968 wrap.setSize(b.width, 0);
9969 st.left = st.bottom = "0";
9973 wrap.setSize(0, b.height);
9974 st.right = st.top = "0";
9978 wrap.setSize(0, b.height);
9980 st.left = st.top = "0";
9981 a = {width: bw, points: pt};
9984 wrap.setSize(b.width, 0);
9985 wrap.setY(b.bottom);
9986 st.left = st.top = "0";
9987 a = {height: bh, points: pt};
9991 st.right = st.bottom = "0";
9992 a = {width: bw, height: bh};
9996 wrap.setY(b.y+b.height);
9997 st.right = st.top = "0";
9998 a = {width: bw, height: bh, points: pt};
10001 wrap.setSize(0, 0);
10002 wrap.setXY([b.right, b.bottom]);
10003 st.left = st.top = "0";
10004 a = {width: bw, height: bh, points: pt};
10007 wrap.setSize(0, 0);
10008 wrap.setX(b.x+b.width);
10009 st.left = st.bottom = "0";
10010 a = {width: bw, height: bh, points: pt};
10013 this.dom.style.visibility = "visible";
10016 arguments.callee.anim = wrap.fxanim(a,
10026 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10027 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10028 * 'hidden') but block elements will still take up space in the document. The element must be removed
10029 * from the DOM using the 'remove' config option if desired. This function automatically handles
10030 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10033 // default: slide the element out to the top
10036 // custom: slide the element out to the right with a 2-second duration
10037 el.slideOut('r', { duration: 2 });
10039 // common config options shown with default values
10047 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10048 * @param {Object} options (optional) Object literal with any of the Fx config options
10049 * @return {Roo.Element} The Element
10051 slideOut : function(anchor, o){
10052 var el = this.getFxEl();
10055 el.queueFx(o, function(){
10057 anchor = anchor || "t";
10059 // restore values after effect
10060 var r = this.getFxRestore();
10062 var b = this.getBox();
10063 // fixed size for slide
10067 var wrap = this.fxWrap(r.pos, o, "visible");
10069 var st = this.dom.style;
10070 st.visibility = "visible";
10071 st.position = "absolute";
10075 var after = function(){
10077 el.setDisplayed(false);
10082 el.fxUnwrap(wrap, r.pos, o);
10084 st.width = r.width;
10085 st.height = r.height;
10090 var a, zero = {to: 0};
10091 switch(anchor.toLowerCase()){
10093 st.left = st.bottom = "0";
10094 a = {height: zero};
10097 st.right = st.top = "0";
10101 st.left = st.top = "0";
10102 a = {width: zero, points: {to:[b.right, b.y]}};
10105 st.left = st.top = "0";
10106 a = {height: zero, points: {to:[b.x, b.bottom]}};
10109 st.right = st.bottom = "0";
10110 a = {width: zero, height: zero};
10113 st.right = st.top = "0";
10114 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10117 st.left = st.top = "0";
10118 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10121 st.left = st.bottom = "0";
10122 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10126 arguments.callee.anim = wrap.fxanim(a,
10136 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10137 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10138 * The element must be removed from the DOM using the 'remove' config option if desired.
10144 // common config options shown with default values
10152 * @param {Object} options (optional) Object literal with any of the Fx config options
10153 * @return {Roo.Element} The Element
10155 puff : function(o){
10156 var el = this.getFxEl();
10159 el.queueFx(o, function(){
10160 this.clearOpacity();
10163 // restore values after effect
10164 var r = this.getFxRestore();
10165 var st = this.dom.style;
10167 var after = function(){
10169 el.setDisplayed(false);
10176 el.setPositioning(r.pos);
10177 st.width = r.width;
10178 st.height = r.height;
10183 var width = this.getWidth();
10184 var height = this.getHeight();
10186 arguments.callee.anim = this.fxanim({
10187 width : {to: this.adjustWidth(width * 2)},
10188 height : {to: this.adjustHeight(height * 2)},
10189 points : {by: [-(width * .5), -(height * .5)]},
10191 fontSize: {to:200, unit: "%"}
10202 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10203 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10204 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10210 // all config options shown with default values
10218 * @param {Object} options (optional) Object literal with any of the Fx config options
10219 * @return {Roo.Element} The Element
10221 switchOff : function(o){
10222 var el = this.getFxEl();
10225 el.queueFx(o, function(){
10226 this.clearOpacity();
10229 // restore values after effect
10230 var r = this.getFxRestore();
10231 var st = this.dom.style;
10233 var after = function(){
10235 el.setDisplayed(false);
10241 el.setPositioning(r.pos);
10242 st.width = r.width;
10243 st.height = r.height;
10248 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10249 this.clearOpacity();
10253 points:{by:[0, this.getHeight() * .5]}
10254 }, o, 'motion', 0.3, 'easeIn', after);
10255 }).defer(100, this);
10262 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10263 * changed using the "attr" config option) and then fading back to the original color. If no original
10264 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10267 // default: highlight background to yellow
10270 // custom: highlight foreground text to blue for 2 seconds
10271 el.highlight("0000ff", { attr: 'color', duration: 2 });
10273 // common config options shown with default values
10274 el.highlight("ffff9c", {
10275 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10276 endColor: (current color) or "ffffff",
10281 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10282 * @param {Object} options (optional) Object literal with any of the Fx config options
10283 * @return {Roo.Element} The Element
10285 highlight : function(color, o){
10286 var el = this.getFxEl();
10289 el.queueFx(o, function(){
10290 color = color || "ffff9c";
10291 attr = o.attr || "backgroundColor";
10293 this.clearOpacity();
10296 var origColor = this.getColor(attr);
10297 var restoreColor = this.dom.style[attr];
10298 endColor = (o.endColor || origColor) || "ffffff";
10300 var after = function(){
10301 el.dom.style[attr] = restoreColor;
10306 a[attr] = {from: color, to: endColor};
10307 arguments.callee.anim = this.fxanim(a,
10317 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10320 // default: a single light blue ripple
10323 // custom: 3 red ripples lasting 3 seconds total
10324 el.frame("ff0000", 3, { duration: 3 });
10326 // common config options shown with default values
10327 el.frame("C3DAF9", 1, {
10328 duration: 1 //duration of entire animation (not each individual ripple)
10329 // Note: Easing is not configurable and will be ignored if included
10332 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10333 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10334 * @param {Object} options (optional) Object literal with any of the Fx config options
10335 * @return {Roo.Element} The Element
10337 frame : function(color, count, o){
10338 var el = this.getFxEl();
10341 el.queueFx(o, function(){
10342 color = color || "#C3DAF9";
10343 if(color.length == 6){
10344 color = "#" + color;
10346 count = count || 1;
10347 duration = o.duration || 1;
10350 var b = this.getBox();
10351 var animFn = function(){
10352 var proxy = this.createProxy({
10355 visbility:"hidden",
10356 position:"absolute",
10357 "z-index":"35000", // yee haw
10358 border:"0px solid " + color
10361 var scale = Roo.isBorderBox ? 2 : 1;
10363 top:{from:b.y, to:b.y - 20},
10364 left:{from:b.x, to:b.x - 20},
10365 borderWidth:{from:0, to:10},
10366 opacity:{from:1, to:0},
10367 height:{from:b.height, to:(b.height + (20*scale))},
10368 width:{from:b.width, to:(b.width + (20*scale))}
10369 }, duration, function(){
10373 animFn.defer((duration/2)*1000, this);
10384 * Creates a pause before any subsequent queued effects begin. If there are
10385 * no effects queued after the pause it will have no effect.
10390 * @param {Number} seconds The length of time to pause (in seconds)
10391 * @return {Roo.Element} The Element
10393 pause : function(seconds){
10394 var el = this.getFxEl();
10397 el.queueFx(o, function(){
10398 setTimeout(function(){
10400 }, seconds * 1000);
10406 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10407 * using the "endOpacity" config option.
10410 // default: fade in from opacity 0 to 100%
10413 // custom: fade in from opacity 0 to 75% over 2 seconds
10414 el.fadeIn({ endOpacity: .75, duration: 2});
10416 // common config options shown with default values
10418 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10423 * @param {Object} options (optional) Object literal with any of the Fx config options
10424 * @return {Roo.Element} The Element
10426 fadeIn : function(o){
10427 var el = this.getFxEl();
10429 el.queueFx(o, function(){
10430 this.setOpacity(0);
10432 this.dom.style.visibility = 'visible';
10433 var to = o.endOpacity || 1;
10434 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10435 o, null, .5, "easeOut", function(){
10437 this.clearOpacity();
10446 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10447 * using the "endOpacity" config option.
10450 // default: fade out from the element's current opacity to 0
10453 // custom: fade out from the element's current opacity to 25% over 2 seconds
10454 el.fadeOut({ endOpacity: .25, duration: 2});
10456 // common config options shown with default values
10458 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10465 * @param {Object} options (optional) Object literal with any of the Fx config options
10466 * @return {Roo.Element} The Element
10468 fadeOut : function(o){
10469 var el = this.getFxEl();
10471 el.queueFx(o, function(){
10472 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10473 o, null, .5, "easeOut", function(){
10474 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10475 this.dom.style.display = "none";
10477 this.dom.style.visibility = "hidden";
10479 this.clearOpacity();
10487 * Animates the transition of an element's dimensions from a starting height/width
10488 * to an ending height/width.
10491 // change height and width to 100x100 pixels
10492 el.scale(100, 100);
10494 // common config options shown with default values. The height and width will default to
10495 // the element's existing values if passed as null.
10498 [element's height], {
10503 * @param {Number} width The new width (pass undefined to keep the original width)
10504 * @param {Number} height The new height (pass undefined to keep the original height)
10505 * @param {Object} options (optional) Object literal with any of the Fx config options
10506 * @return {Roo.Element} The Element
10508 scale : function(w, h, o){
10509 this.shift(Roo.apply({}, o, {
10517 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10518 * Any of these properties not specified in the config object will not be changed. This effect
10519 * requires that at least one new dimension, position or opacity setting must be passed in on
10520 * the config object in order for the function to have any effect.
10523 // slide the element horizontally to x position 200 while changing the height and opacity
10524 el.shift({ x: 200, height: 50, opacity: .8 });
10526 // common config options shown with default values.
10528 width: [element's width],
10529 height: [element's height],
10530 x: [element's x position],
10531 y: [element's y position],
10532 opacity: [element's opacity],
10537 * @param {Object} options Object literal with any of the Fx config options
10538 * @return {Roo.Element} The Element
10540 shift : function(o){
10541 var el = this.getFxEl();
10543 el.queueFx(o, function(){
10544 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10545 if(w !== undefined){
10546 a.width = {to: this.adjustWidth(w)};
10548 if(h !== undefined){
10549 a.height = {to: this.adjustHeight(h)};
10551 if(x !== undefined || y !== undefined){
10553 x !== undefined ? x : this.getX(),
10554 y !== undefined ? y : this.getY()
10557 if(op !== undefined){
10558 a.opacity = {to: op};
10560 if(o.xy !== undefined){
10561 a.points = {to: o.xy};
10563 arguments.callee.anim = this.fxanim(a,
10564 o, 'motion', .35, "easeOut", function(){
10572 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10573 * ending point of the effect.
10576 // default: slide the element downward while fading out
10579 // custom: slide the element out to the right with a 2-second duration
10580 el.ghost('r', { duration: 2 });
10582 // common config options shown with default values
10590 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10591 * @param {Object} options (optional) Object literal with any of the Fx config options
10592 * @return {Roo.Element} The Element
10594 ghost : function(anchor, o){
10595 var el = this.getFxEl();
10598 el.queueFx(o, function(){
10599 anchor = anchor || "b";
10601 // restore values after effect
10602 var r = this.getFxRestore();
10603 var w = this.getWidth(),
10604 h = this.getHeight();
10606 var st = this.dom.style;
10608 var after = function(){
10610 el.setDisplayed(false);
10616 el.setPositioning(r.pos);
10617 st.width = r.width;
10618 st.height = r.height;
10623 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10624 switch(anchor.toLowerCase()){
10651 arguments.callee.anim = this.fxanim(a,
10661 * Ensures that all effects queued after syncFx is called on the element are
10662 * run concurrently. This is the opposite of {@link #sequenceFx}.
10663 * @return {Roo.Element} The Element
10665 syncFx : function(){
10666 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10675 * Ensures that all effects queued after sequenceFx is called on the element are
10676 * run in sequence. This is the opposite of {@link #syncFx}.
10677 * @return {Roo.Element} The Element
10679 sequenceFx : function(){
10680 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10682 concurrent : false,
10689 nextFx : function(){
10690 var ef = this.fxQueue[0];
10697 * Returns true if the element has any effects actively running or queued, else returns false.
10698 * @return {Boolean} True if element has active effects, else false
10700 hasActiveFx : function(){
10701 return this.fxQueue && this.fxQueue[0];
10705 * Stops any running effects and clears the element's internal effects queue if it contains
10706 * any additional effects that haven't started yet.
10707 * @return {Roo.Element} The Element
10709 stopFx : function(){
10710 if(this.hasActiveFx()){
10711 var cur = this.fxQueue[0];
10712 if(cur && cur.anim && cur.anim.isAnimated()){
10713 this.fxQueue = [cur]; // clear out others
10714 cur.anim.stop(true);
10721 beforeFx : function(o){
10722 if(this.hasActiveFx() && !o.concurrent){
10733 * Returns true if the element is currently blocking so that no other effect can be queued
10734 * until this effect is finished, else returns false if blocking is not set. This is commonly
10735 * used to ensure that an effect initiated by a user action runs to completion prior to the
10736 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10737 * @return {Boolean} True if blocking, else false
10739 hasFxBlock : function(){
10740 var q = this.fxQueue;
10741 return q && q[0] && q[0].block;
10745 queueFx : function(o, fn){
10749 if(!this.hasFxBlock()){
10750 Roo.applyIf(o, this.fxDefaults);
10752 var run = this.beforeFx(o);
10753 fn.block = o.block;
10754 this.fxQueue.push(fn);
10766 fxWrap : function(pos, o, vis){
10768 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10771 wrapXY = this.getXY();
10773 var div = document.createElement("div");
10774 div.style.visibility = vis;
10775 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10776 wrap.setPositioning(pos);
10777 if(wrap.getStyle("position") == "static"){
10778 wrap.position("relative");
10780 this.clearPositioning('auto');
10782 wrap.dom.appendChild(this.dom);
10784 wrap.setXY(wrapXY);
10791 fxUnwrap : function(wrap, pos, o){
10792 this.clearPositioning();
10793 this.setPositioning(pos);
10795 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10801 getFxRestore : function(){
10802 var st = this.dom.style;
10803 return {pos: this.getPositioning(), width: st.width, height : st.height};
10807 afterFx : function(o){
10809 this.applyStyles(o.afterStyle);
10812 this.addClass(o.afterCls);
10814 if(o.remove === true){
10817 Roo.callback(o.callback, o.scope, [this]);
10819 this.fxQueue.shift();
10825 getFxEl : function(){ // support for composite element fx
10826 return Roo.get(this.dom);
10830 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10831 animType = animType || 'run';
10833 var anim = Roo.lib.Anim[animType](
10835 (opt.duration || defaultDur) || .35,
10836 (opt.easing || defaultEase) || 'easeOut',
10838 Roo.callback(cb, this);
10847 // backwords compat
10848 Roo.Fx.resize = Roo.Fx.scale;
10850 //When included, Roo.Fx is automatically applied to Element so that all basic
10851 //effects are available directly via the Element API
10852 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10854 * Ext JS Library 1.1.1
10855 * Copyright(c) 2006-2007, Ext JS, LLC.
10857 * Originally Released Under LGPL - original licence link has changed is not relivant.
10860 * <script type="text/javascript">
10865 * @class Roo.CompositeElement
10866 * Standard composite class. Creates a Roo.Element for every element in the collection.
10868 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10869 * actions will be performed on all the elements in this collection.</b>
10871 * All methods return <i>this</i> and can be chained.
10873 var els = Roo.select("#some-el div.some-class", true);
10874 // or select directly from an existing element
10875 var el = Roo.get('some-el');
10876 el.select('div.some-class', true);
10878 els.setWidth(100); // all elements become 100 width
10879 els.hide(true); // all elements fade out and hide
10881 els.setWidth(100).hide(true);
10884 Roo.CompositeElement = function(els){
10885 this.elements = [];
10886 this.addElements(els);
10888 Roo.CompositeElement.prototype = {
10890 addElements : function(els){
10891 if(!els) return this;
10892 if(typeof els == "string"){
10893 els = Roo.Element.selectorFunction(els);
10895 var yels = this.elements;
10896 var index = yels.length-1;
10897 for(var i = 0, len = els.length; i < len; i++) {
10898 yels[++index] = Roo.get(els[i]);
10904 * Clears this composite and adds the elements returned by the passed selector.
10905 * @param {String/Array} els A string CSS selector, an array of elements or an element
10906 * @return {CompositeElement} this
10908 fill : function(els){
10909 this.elements = [];
10915 * Filters this composite to only elements that match the passed selector.
10916 * @param {String} selector A string CSS selector
10917 * @return {CompositeElement} this
10919 filter : function(selector){
10921 this.each(function(el){
10922 if(el.is(selector)){
10923 els[els.length] = el.dom;
10930 invoke : function(fn, args){
10931 var els = this.elements;
10932 for(var i = 0, len = els.length; i < len; i++) {
10933 Roo.Element.prototype[fn].apply(els[i], args);
10938 * Adds elements to this composite.
10939 * @param {String/Array} els A string CSS selector, an array of elements or an element
10940 * @return {CompositeElement} this
10942 add : function(els){
10943 if(typeof els == "string"){
10944 this.addElements(Roo.Element.selectorFunction(els));
10945 }else if(els.length !== undefined){
10946 this.addElements(els);
10948 this.addElements([els]);
10953 * Calls the passed function passing (el, this, index) for each element in this composite.
10954 * @param {Function} fn The function to call
10955 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10956 * @return {CompositeElement} this
10958 each : function(fn, scope){
10959 var els = this.elements;
10960 for(var i = 0, len = els.length; i < len; i++){
10961 if(fn.call(scope || els[i], els[i], this, i) === false) {
10969 * Returns the Element object at the specified index
10970 * @param {Number} index
10971 * @return {Roo.Element}
10973 item : function(index){
10974 return this.elements[index] || null;
10978 * Returns the first Element
10979 * @return {Roo.Element}
10981 first : function(){
10982 return this.item(0);
10986 * Returns the last Element
10987 * @return {Roo.Element}
10990 return this.item(this.elements.length-1);
10994 * Returns the number of elements in this composite
10997 getCount : function(){
10998 return this.elements.length;
11002 * Returns true if this composite contains the passed element
11005 contains : function(el){
11006 return this.indexOf(el) !== -1;
11010 * Returns true if this composite contains the passed element
11013 indexOf : function(el){
11014 return this.elements.indexOf(Roo.get(el));
11019 * Removes the specified element(s).
11020 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11021 * or an array of any of those.
11022 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11023 * @return {CompositeElement} this
11025 removeElement : function(el, removeDom){
11026 if(el instanceof Array){
11027 for(var i = 0, len = el.length; i < len; i++){
11028 this.removeElement(el[i]);
11032 var index = typeof el == 'number' ? el : this.indexOf(el);
11035 var d = this.elements[index];
11039 d.parentNode.removeChild(d);
11042 this.elements.splice(index, 1);
11048 * Replaces the specified element with the passed element.
11049 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11051 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11052 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11053 * @return {CompositeElement} this
11055 replaceElement : function(el, replacement, domReplace){
11056 var index = typeof el == 'number' ? el : this.indexOf(el);
11059 this.elements[index].replaceWith(replacement);
11061 this.elements.splice(index, 1, Roo.get(replacement))
11068 * Removes all elements.
11070 clear : function(){
11071 this.elements = [];
11075 Roo.CompositeElement.createCall = function(proto, fnName){
11076 if(!proto[fnName]){
11077 proto[fnName] = function(){
11078 return this.invoke(fnName, arguments);
11082 for(var fnName in Roo.Element.prototype){
11083 if(typeof Roo.Element.prototype[fnName] == "function"){
11084 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11090 * Ext JS Library 1.1.1
11091 * Copyright(c) 2006-2007, Ext JS, LLC.
11093 * Originally Released Under LGPL - original licence link has changed is not relivant.
11096 * <script type="text/javascript">
11100 * @class Roo.CompositeElementLite
11101 * @extends Roo.CompositeElement
11102 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11104 var els = Roo.select("#some-el div.some-class");
11105 // or select directly from an existing element
11106 var el = Roo.get('some-el');
11107 el.select('div.some-class');
11109 els.setWidth(100); // all elements become 100 width
11110 els.hide(true); // all elements fade out and hide
11112 els.setWidth(100).hide(true);
11113 </code></pre><br><br>
11114 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11115 * actions will be performed on all the elements in this collection.</b>
11117 Roo.CompositeElementLite = function(els){
11118 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11119 this.el = new Roo.Element.Flyweight();
11121 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11122 addElements : function(els){
11124 if(els instanceof Array){
11125 this.elements = this.elements.concat(els);
11127 var yels = this.elements;
11128 var index = yels.length-1;
11129 for(var i = 0, len = els.length; i < len; i++) {
11130 yels[++index] = els[i];
11136 invoke : function(fn, args){
11137 var els = this.elements;
11139 for(var i = 0, len = els.length; i < len; i++) {
11141 Roo.Element.prototype[fn].apply(el, args);
11146 * Returns a flyweight Element of the dom element object at the specified index
11147 * @param {Number} index
11148 * @return {Roo.Element}
11150 item : function(index){
11151 if(!this.elements[index]){
11154 this.el.dom = this.elements[index];
11158 // fixes scope with flyweight
11159 addListener : function(eventName, handler, scope, opt){
11160 var els = this.elements;
11161 for(var i = 0, len = els.length; i < len; i++) {
11162 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11168 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11169 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11170 * a reference to the dom node, use el.dom.</b>
11171 * @param {Function} fn The function to call
11172 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11173 * @return {CompositeElement} this
11175 each : function(fn, scope){
11176 var els = this.elements;
11178 for(var i = 0, len = els.length; i < len; i++){
11180 if(fn.call(scope || el, el, this, i) === false){
11187 indexOf : function(el){
11188 return this.elements.indexOf(Roo.getDom(el));
11191 replaceElement : function(el, replacement, domReplace){
11192 var index = typeof el == 'number' ? el : this.indexOf(el);
11194 replacement = Roo.getDom(replacement);
11196 var d = this.elements[index];
11197 d.parentNode.insertBefore(replacement, d);
11198 d.parentNode.removeChild(d);
11200 this.elements.splice(index, 1, replacement);
11205 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11209 * Ext JS Library 1.1.1
11210 * Copyright(c) 2006-2007, Ext JS, LLC.
11212 * Originally Released Under LGPL - original licence link has changed is not relivant.
11215 * <script type="text/javascript">
11221 * @class Roo.data.Connection
11222 * @extends Roo.util.Observable
11223 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11224 * either to a configured URL, or to a URL specified at request time.<br><br>
11226 * Requests made by this class are asynchronous, and will return immediately. No data from
11227 * the server will be available to the statement immediately following the {@link #request} call.
11228 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11230 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11231 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11232 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11233 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11234 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11235 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11236 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11237 * standard DOM methods.
11239 * @param {Object} config a configuration object.
11241 Roo.data.Connection = function(config){
11242 Roo.apply(this, config);
11245 * @event beforerequest
11246 * Fires before a network request is made to retrieve a data object.
11247 * @param {Connection} conn This Connection object.
11248 * @param {Object} options The options config object passed to the {@link #request} method.
11250 "beforerequest" : true,
11252 * @event requestcomplete
11253 * Fires if the request was successfully completed.
11254 * @param {Connection} conn This Connection object.
11255 * @param {Object} response The XHR object containing the response data.
11256 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11257 * @param {Object} options The options config object passed to the {@link #request} method.
11259 "requestcomplete" : true,
11261 * @event requestexception
11262 * Fires if an error HTTP status was returned from the server.
11263 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11264 * @param {Connection} conn This Connection object.
11265 * @param {Object} response The XHR object containing the response data.
11266 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11267 * @param {Object} options The options config object passed to the {@link #request} method.
11269 "requestexception" : true
11271 Roo.data.Connection.superclass.constructor.call(this);
11274 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11276 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11279 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11280 * extra parameters to each request made by this object. (defaults to undefined)
11283 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11284 * to each request made by this object. (defaults to undefined)
11287 * @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)
11290 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11294 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11300 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11303 disableCaching: true,
11306 * Sends an HTTP request to a remote server.
11307 * @param {Object} options An object which may contain the following properties:<ul>
11308 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11309 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11310 * request, a url encoded string or a function to call to get either.</li>
11311 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11312 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11313 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11314 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11315 * <li>options {Object} The parameter to the request call.</li>
11316 * <li>success {Boolean} True if the request succeeded.</li>
11317 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11319 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11320 * The callback is passed the following parameters:<ul>
11321 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11322 * <li>options {Object} The parameter to the request call.</li>
11324 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11325 * The callback is passed the following parameters:<ul>
11326 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11327 * <li>options {Object} The parameter to the request call.</li>
11329 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11330 * for the callback function. Defaults to the browser window.</li>
11331 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11332 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11333 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11334 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11335 * params for the post data. Any params will be appended to the URL.</li>
11336 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11338 * @return {Number} transactionId
11340 request : function(o){
11341 if(this.fireEvent("beforerequest", this, o) !== false){
11344 if(typeof p == "function"){
11345 p = p.call(o.scope||window, o);
11347 if(typeof p == "object"){
11348 p = Roo.urlEncode(o.params);
11350 if(this.extraParams){
11351 var extras = Roo.urlEncode(this.extraParams);
11352 p = p ? (p + '&' + extras) : extras;
11355 var url = o.url || this.url;
11356 if(typeof url == 'function'){
11357 url = url.call(o.scope||window, o);
11361 var form = Roo.getDom(o.form);
11362 url = url || form.action;
11364 var enctype = form.getAttribute("enctype");
11365 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11366 return this.doFormUpload(o, p, url);
11368 var f = Roo.lib.Ajax.serializeForm(form);
11369 p = p ? (p + '&' + f) : f;
11372 var hs = o.headers;
11373 if(this.defaultHeaders){
11374 hs = Roo.apply(hs || {}, this.defaultHeaders);
11381 success: this.handleResponse,
11382 failure: this.handleFailure,
11384 argument: {options: o},
11385 timeout : this.timeout
11388 var method = o.method||this.method||(p ? "POST" : "GET");
11390 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11391 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11394 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11398 }else if(this.autoAbort !== false){
11402 if((method == 'GET' && p) || o.xmlData){
11403 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11406 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11407 return this.transId;
11409 Roo.callback(o.callback, o.scope, [o, null, null]);
11415 * Determine whether this object has a request outstanding.
11416 * @param {Number} transactionId (Optional) defaults to the last transaction
11417 * @return {Boolean} True if there is an outstanding request.
11419 isLoading : function(transId){
11421 return Roo.lib.Ajax.isCallInProgress(transId);
11423 return this.transId ? true : false;
11428 * Aborts any outstanding request.
11429 * @param {Number} transactionId (Optional) defaults to the last transaction
11431 abort : function(transId){
11432 if(transId || this.isLoading()){
11433 Roo.lib.Ajax.abort(transId || this.transId);
11438 handleResponse : function(response){
11439 this.transId = false;
11440 var options = response.argument.options;
11441 response.argument = options ? options.argument : null;
11442 this.fireEvent("requestcomplete", this, response, options);
11443 Roo.callback(options.success, options.scope, [response, options]);
11444 Roo.callback(options.callback, options.scope, [options, true, response]);
11448 handleFailure : function(response, e){
11449 this.transId = false;
11450 var options = response.argument.options;
11451 response.argument = options ? options.argument : null;
11452 this.fireEvent("requestexception", this, response, options, e);
11453 Roo.callback(options.failure, options.scope, [response, options]);
11454 Roo.callback(options.callback, options.scope, [options, false, response]);
11458 doFormUpload : function(o, ps, url){
11460 var frame = document.createElement('iframe');
11463 frame.className = 'x-hidden';
11465 frame.src = Roo.SSL_SECURE_URL;
11467 document.body.appendChild(frame);
11470 document.frames[id].name = id;
11473 var form = Roo.getDom(o.form);
11475 form.method = 'POST';
11476 form.enctype = form.encoding = 'multipart/form-data';
11482 if(ps){ // add dynamic params
11484 ps = Roo.urlDecode(ps, false);
11486 if(ps.hasOwnProperty(k)){
11487 hd = document.createElement('input');
11488 hd.type = 'hidden';
11491 form.appendChild(hd);
11498 var r = { // bogus response object
11503 r.argument = o ? o.argument : null;
11508 doc = frame.contentWindow.document;
11510 doc = (frame.contentDocument || window.frames[id].document);
11512 if(doc && doc.body){
11513 r.responseText = doc.body.innerHTML;
11515 if(doc && doc.XMLDocument){
11516 r.responseXML = doc.XMLDocument;
11518 r.responseXML = doc;
11525 Roo.EventManager.removeListener(frame, 'load', cb, this);
11527 this.fireEvent("requestcomplete", this, r, o);
11528 Roo.callback(o.success, o.scope, [r, o]);
11529 Roo.callback(o.callback, o.scope, [o, true, r]);
11531 setTimeout(function(){document.body.removeChild(frame);}, 100);
11534 Roo.EventManager.on(frame, 'load', cb, this);
11537 if(hiddens){ // remove dynamic params
11538 for(var i = 0, len = hiddens.length; i < len; i++){
11539 form.removeChild(hiddens[i]);
11547 * @extends Roo.data.Connection
11548 * Global Ajax request class.
11552 Roo.Ajax = new Roo.data.Connection({
11555 * @cfg {String} url @hide
11558 * @cfg {Object} extraParams @hide
11561 * @cfg {Object} defaultHeaders @hide
11564 * @cfg {String} method (Optional) @hide
11567 * @cfg {Number} timeout (Optional) @hide
11570 * @cfg {Boolean} autoAbort (Optional) @hide
11574 * @cfg {Boolean} disableCaching (Optional) @hide
11578 * @property disableCaching
11579 * True to add a unique cache-buster param to GET requests. (defaults to true)
11584 * The default URL to be used for requests to the server. (defaults to undefined)
11588 * @property extraParams
11589 * An object containing properties which are used as
11590 * extra parameters to each request made by this object. (defaults to undefined)
11594 * @property defaultHeaders
11595 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11600 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11604 * @property timeout
11605 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11610 * @property autoAbort
11611 * Whether a new request should abort any pending requests. (defaults to false)
11617 * Serialize the passed form into a url encoded string
11618 * @param {String/HTMLElement} form
11621 serializeForm : function(form){
11622 return Roo.lib.Ajax.serializeForm(form);
11626 * Ext JS Library 1.1.1
11627 * Copyright(c) 2006-2007, Ext JS, LLC.
11629 * Originally Released Under LGPL - original licence link has changed is not relivant.
11632 * <script type="text/javascript">
11636 * Global Ajax request class.
11639 * @extends Roo.data.Connection
11642 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11643 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11644 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11645 * @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)
11646 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11647 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11648 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11650 Roo.Ajax = new Roo.data.Connection({
11659 * Serialize the passed form into a url encoded string
11661 * @param {String/HTMLElement} form
11664 serializeForm : function(form){
11665 return Roo.lib.Ajax.serializeForm(form);
11669 * Ext JS Library 1.1.1
11670 * Copyright(c) 2006-2007, Ext JS, LLC.
11672 * Originally Released Under LGPL - original licence link has changed is not relivant.
11675 * <script type="text/javascript">
11680 * @class Roo.UpdateManager
11681 * @extends Roo.util.Observable
11682 * Provides AJAX-style update for Element object.<br><br>
11685 * // Get it from a Roo.Element object
11686 * var el = Roo.get("foo");
11687 * var mgr = el.getUpdateManager();
11688 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11690 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11692 * // or directly (returns the same UpdateManager instance)
11693 * var mgr = new Roo.UpdateManager("myElementId");
11694 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11695 * mgr.on("update", myFcnNeedsToKnow);
11697 // short handed call directly from the element object
11698 Roo.get("foo").load({
11702 text: "Loading Foo..."
11706 * Create new UpdateManager directly.
11707 * @param {String/HTMLElement/Roo.Element} el The element to update
11708 * @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).
11710 Roo.UpdateManager = function(el, forceNew){
11712 if(!forceNew && el.updateManager){
11713 return el.updateManager;
11716 * The Element object
11717 * @type Roo.Element
11721 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11724 this.defaultUrl = null;
11728 * @event beforeupdate
11729 * Fired before an update is made, return false from your handler and the update is cancelled.
11730 * @param {Roo.Element} el
11731 * @param {String/Object/Function} url
11732 * @param {String/Object} params
11734 "beforeupdate": true,
11737 * Fired after successful update is made.
11738 * @param {Roo.Element} el
11739 * @param {Object} oResponseObject The response Object
11744 * Fired on update failure.
11745 * @param {Roo.Element} el
11746 * @param {Object} oResponseObject The response Object
11750 var d = Roo.UpdateManager.defaults;
11752 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11755 this.sslBlankUrl = d.sslBlankUrl;
11757 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11760 this.disableCaching = d.disableCaching;
11762 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11765 this.indicatorText = d.indicatorText;
11767 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11770 this.showLoadIndicator = d.showLoadIndicator;
11772 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11775 this.timeout = d.timeout;
11778 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11781 this.loadScripts = d.loadScripts;
11784 * Transaction object of current executing transaction
11786 this.transaction = null;
11791 this.autoRefreshProcId = null;
11793 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11796 this.refreshDelegate = this.refresh.createDelegate(this);
11798 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11801 this.updateDelegate = this.update.createDelegate(this);
11803 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11806 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11810 this.successDelegate = this.processSuccess.createDelegate(this);
11814 this.failureDelegate = this.processFailure.createDelegate(this);
11816 if(!this.renderer){
11818 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11820 this.renderer = new Roo.UpdateManager.BasicRenderer();
11823 Roo.UpdateManager.superclass.constructor.call(this);
11826 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11828 * Get the Element this UpdateManager is bound to
11829 * @return {Roo.Element} The element
11831 getEl : function(){
11835 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11836 * @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:
11839 url: "your-url.php",<br/>
11840 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11841 callback: yourFunction,<br/>
11842 scope: yourObject, //(optional scope) <br/>
11843 discardUrl: false, <br/>
11844 nocache: false,<br/>
11845 text: "Loading...",<br/>
11847 scripts: false<br/>
11850 * The only required property is url. The optional properties nocache, text and scripts
11851 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11852 * @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}
11853 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11854 * @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.
11856 update : function(url, params, callback, discardUrl){
11857 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11858 var method = this.method, cfg;
11859 if(typeof url == "object"){ // must be config object
11862 params = params || cfg.params;
11863 callback = callback || cfg.callback;
11864 discardUrl = discardUrl || cfg.discardUrl;
11865 if(callback && cfg.scope){
11866 callback = callback.createDelegate(cfg.scope);
11868 if(typeof cfg.method != "undefined"){method = cfg.method;};
11869 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11870 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11871 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11872 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11874 this.showLoading();
11876 this.defaultUrl = url;
11878 if(typeof url == "function"){
11879 url = url.call(this);
11882 method = method || (params ? "POST" : "GET");
11883 if(method == "GET"){
11884 url = this.prepareUrl(url);
11887 var o = Roo.apply(cfg ||{}, {
11890 success: this.successDelegate,
11891 failure: this.failureDelegate,
11892 callback: undefined,
11893 timeout: (this.timeout*1000),
11894 argument: {"url": url, "form": null, "callback": callback, "params": params}
11897 this.transaction = Roo.Ajax.request(o);
11902 * 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.
11903 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11904 * @param {String/HTMLElement} form The form Id or form element
11905 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11906 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11907 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11909 formUpdate : function(form, url, reset, callback){
11910 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11911 if(typeof url == "function"){
11912 url = url.call(this);
11914 form = Roo.getDom(form);
11915 this.transaction = Roo.Ajax.request({
11918 success: this.successDelegate,
11919 failure: this.failureDelegate,
11920 timeout: (this.timeout*1000),
11921 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11923 this.showLoading.defer(1, this);
11928 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11929 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11931 refresh : function(callback){
11932 if(this.defaultUrl == null){
11935 this.update(this.defaultUrl, null, callback, true);
11939 * Set this element to auto refresh.
11940 * @param {Number} interval How often to update (in seconds).
11941 * @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)
11942 * @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}
11943 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11944 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11946 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11948 this.update(url || this.defaultUrl, params, callback, true);
11950 if(this.autoRefreshProcId){
11951 clearInterval(this.autoRefreshProcId);
11953 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11957 * Stop auto refresh on this element.
11959 stopAutoRefresh : function(){
11960 if(this.autoRefreshProcId){
11961 clearInterval(this.autoRefreshProcId);
11962 delete this.autoRefreshProcId;
11966 isAutoRefreshing : function(){
11967 return this.autoRefreshProcId ? true : false;
11970 * Called to update the element to "Loading" state. Override to perform custom action.
11972 showLoading : function(){
11973 if(this.showLoadIndicator){
11974 this.el.update(this.indicatorText);
11979 * Adds unique parameter to query string if disableCaching = true
11982 prepareUrl : function(url){
11983 if(this.disableCaching){
11984 var append = "_dc=" + (new Date().getTime());
11985 if(url.indexOf("?") !== -1){
11986 url += "&" + append;
11988 url += "?" + append;
11997 processSuccess : function(response){
11998 this.transaction = null;
11999 if(response.argument.form && response.argument.reset){
12000 try{ // put in try/catch since some older FF releases had problems with this
12001 response.argument.form.reset();
12004 if(this.loadScripts){
12005 this.renderer.render(this.el, response, this,
12006 this.updateComplete.createDelegate(this, [response]));
12008 this.renderer.render(this.el, response, this);
12009 this.updateComplete(response);
12013 updateComplete : function(response){
12014 this.fireEvent("update", this.el, response);
12015 if(typeof response.argument.callback == "function"){
12016 response.argument.callback(this.el, true, response);
12023 processFailure : function(response){
12024 this.transaction = null;
12025 this.fireEvent("failure", this.el, response);
12026 if(typeof response.argument.callback == "function"){
12027 response.argument.callback(this.el, false, response);
12032 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12033 * @param {Object} renderer The object implementing the render() method
12035 setRenderer : function(renderer){
12036 this.renderer = renderer;
12039 getRenderer : function(){
12040 return this.renderer;
12044 * Set the defaultUrl used for updates
12045 * @param {String/Function} defaultUrl The url or a function to call to get the url
12047 setDefaultUrl : function(defaultUrl){
12048 this.defaultUrl = defaultUrl;
12052 * Aborts the executing transaction
12054 abort : function(){
12055 if(this.transaction){
12056 Roo.Ajax.abort(this.transaction);
12061 * Returns true if an update is in progress
12062 * @return {Boolean}
12064 isUpdating : function(){
12065 if(this.transaction){
12066 return Roo.Ajax.isLoading(this.transaction);
12073 * @class Roo.UpdateManager.defaults
12074 * @static (not really - but it helps the doc tool)
12075 * The defaults collection enables customizing the default properties of UpdateManager
12077 Roo.UpdateManager.defaults = {
12079 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12085 * True to process scripts by default (Defaults to false).
12088 loadScripts : false,
12091 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12094 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12096 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12099 disableCaching : false,
12101 * Whether to show indicatorText when loading (Defaults to true).
12104 showLoadIndicator : true,
12106 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12109 indicatorText : '<div class="loading-indicator">Loading...</div>'
12113 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12115 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12116 * @param {String/HTMLElement/Roo.Element} el The element to update
12117 * @param {String} url The url
12118 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12119 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12122 * @member Roo.UpdateManager
12124 Roo.UpdateManager.updateElement = function(el, url, params, options){
12125 var um = Roo.get(el, true).getUpdateManager();
12126 Roo.apply(um, options);
12127 um.update(url, params, options ? options.callback : null);
12129 // alias for backwards compat
12130 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12132 * @class Roo.UpdateManager.BasicRenderer
12133 * Default Content renderer. Updates the elements innerHTML with the responseText.
12135 Roo.UpdateManager.BasicRenderer = function(){};
12137 Roo.UpdateManager.BasicRenderer.prototype = {
12139 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12140 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12141 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12142 * @param {Roo.Element} el The element being rendered
12143 * @param {Object} response The YUI Connect response object
12144 * @param {UpdateManager} updateManager The calling update manager
12145 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12147 render : function(el, response, updateManager, callback){
12148 el.update(response.responseText, updateManager.loadScripts, callback);
12154 * (c)) Alan Knowles
12160 * @class Roo.DomTemplate
12161 * @extends Roo.Template
12162 * An effort at a dom based template engine..
12164 * Similar to XTemplate, except it uses dom parsing to create the template..
12166 * Supported features:
12171 {a_variable} - output encoded.
12172 {a_variable.format:("Y-m-d")} - call a method on the variable
12173 {a_variable:raw} - unencoded output
12174 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12175 {a_variable:this.method_on_template(...)} - call a method on the template object.
12180 <div roo-for="a_variable or condition.."></div>
12181 <div roo-if="a_variable or condition"></div>
12182 <div roo-exec="some javascript"></div>
12183 <div roo-name="named_template"></div>
12188 Roo.DomTemplate = function()
12190 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12197 Roo.extend(Roo.DomTemplate, Roo.Template, {
12199 * id counter for sub templates.
12203 * flag to indicate if dom parser is inside a pre,
12204 * it will strip whitespace if not.
12209 * The various sub templates
12217 * basic tag replacing syntax
12220 * // you can fake an object call by doing this
12224 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\}|\%7D)/g,
12225 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12227 iterChild : function (node, method) {
12229 var oldPre = this.inPre;
12230 if (node.tagName == 'PRE') {
12233 for( var i = 0; i < node.childNodes.length; i++) {
12234 method.call(this, node.childNodes[i]);
12236 this.inPre = oldPre;
12242 * compile the template
12244 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12247 compile: function()
12251 // covert the html into DOM...
12253 var div = document.createElement('div');
12254 div.innerHTML = this.html ;
12258 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12260 var tpls = this.tpls;
12262 // create a top level template from the snippet..
12264 //Roo.log(div.innerHTML);
12271 body : div.innerHTML,
12284 Roo.each(tpls, function(tp){
12285 this.compileTpl(tp);
12286 this.tpls[tp.id] = tp;
12289 this.master = tpls[0];
12295 compileNode : function(node, istop) {
12300 // skip anything not a tag..
12301 if (node.nodeType != 1) {
12302 if (node.nodeType == 3 && !this.inPre) {
12303 // reduce white space..
12304 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12327 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12328 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12329 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12330 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12336 // just itterate children..
12337 this.iterChild(node,this.compileNode);
12340 tpl.uid = this.id++;
12341 tpl.value = node.getAttribute('roo-' + tpl.attr);
12342 node.removeAttribute('roo-'+ tpl.attr);
12343 if (tpl.attr != 'name') {
12344 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12345 node.parentNode.replaceChild(placeholder, node);
12348 var placeholder = document.createElement('span');
12349 placeholder.className = 'roo-tpl-' + tpl.value;
12350 node.parentNode.replaceChild(placeholder, node);
12353 // parent now sees '{domtplXXXX}
12354 this.iterChild(node,this.compileNode);
12356 // we should now have node body...
12357 var div = document.createElement('div');
12358 div.appendChild(node);
12360 // this has the unfortunate side effect of converting tagged attributes
12361 // eg. href="{...}" into %7C...%7D
12362 // this has been fixed by searching for those combo's although it's a bit hacky..
12365 tpl.body = div.innerHTML;
12372 switch (tpl.value) {
12373 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12374 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12375 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12380 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12384 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12388 tpl.id = tpl.value; // replace non characters???
12394 this.tpls.push(tpl);
12404 * Compile a segment of the template into a 'sub-template'
12410 compileTpl : function(tpl)
12412 var fm = Roo.util.Format;
12413 var useF = this.disableFormats !== true;
12415 var sep = Roo.isGecko ? "+\n" : ",\n";
12417 var undef = function(str) {
12418 Roo.debug && Roo.log("Property not found :" + str);
12422 //Roo.log(tpl.body);
12426 var fn = function(m, lbrace, name, format, args)
12429 //Roo.log(arguments);
12430 args = args ? args.replace(/\\'/g,"'") : args;
12431 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12432 if (typeof(format) == 'undefined') {
12433 format = 'htmlEncode';
12435 if (format == 'raw' ) {
12439 if(name.substr(0, 6) == 'domtpl'){
12440 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12443 // build an array of options to determine if value is undefined..
12445 // basically get 'xxxx.yyyy' then do
12446 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12447 // (function () { Roo.log("Property not found"); return ''; })() :
12452 Roo.each(name.split('.'), function(st) {
12453 lookfor += (lookfor.length ? '.': '') + st;
12454 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12457 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12460 if(format && useF){
12462 args = args ? ',' + args : "";
12464 if(format.substr(0, 5) != "this."){
12465 format = "fm." + format + '(';
12467 format = 'this.call("'+ format.substr(5) + '", ';
12471 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12475 // called with xxyx.yuu:(test,test)
12477 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12479 // raw.. - :raw modifier..
12480 return "'"+ sep + udef_st + name + ")"+sep+"'";
12484 // branched to use + in gecko and [].join() in others
12486 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12487 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12490 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12491 body.push(tpl.body.replace(/(\r\n|\n)/g,
12492 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12493 body.push("'].join('');};};");
12494 body = body.join('');
12497 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12499 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12506 * same as applyTemplate, except it's done to one of the subTemplates
12507 * when using named templates, you can do:
12509 * var str = pl.applySubTemplate('your-name', values);
12512 * @param {Number} id of the template
12513 * @param {Object} values to apply to template
12514 * @param {Object} parent (normaly the instance of this object)
12516 applySubTemplate : function(id, values, parent)
12520 var t = this.tpls[id];
12524 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12525 Roo.log('if call on ' + t.value + ' return false');
12529 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12536 if(t.execCall && t.execCall.call(this, values, parent)){
12540 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12546 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12547 parent = t.target ? values : parent;
12548 if(t.forCall && vs instanceof Array){
12550 for(var i = 0, len = vs.length; i < len; i++){
12552 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12554 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12556 //Roo.log(t.compiled);
12560 return buf.join('');
12563 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12568 return t.compiled.call(this, vs, parent);
12570 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12572 //Roo.log(t.compiled);
12580 applyTemplate : function(values){
12581 return this.master.compiled.call(this, values, {});
12582 //var s = this.subs;
12585 apply : function(){
12586 return this.applyTemplate.apply(this, arguments);
12591 Roo.DomTemplate.from = function(el){
12592 el = Roo.getDom(el);
12593 return new Roo.Domtemplate(el.value || el.innerHTML);
12596 * Ext JS Library 1.1.1
12597 * Copyright(c) 2006-2007, Ext JS, LLC.
12599 * Originally Released Under LGPL - original licence link has changed is not relivant.
12602 * <script type="text/javascript">
12606 * @class Roo.util.DelayedTask
12607 * Provides a convenient method of performing setTimeout where a new
12608 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12609 * You can use this class to buffer
12610 * the keypress events for a certain number of milliseconds, and perform only if they stop
12611 * for that amount of time.
12612 * @constructor The parameters to this constructor serve as defaults and are not required.
12613 * @param {Function} fn (optional) The default function to timeout
12614 * @param {Object} scope (optional) The default scope of that timeout
12615 * @param {Array} args (optional) The default Array of arguments
12617 Roo.util.DelayedTask = function(fn, scope, args){
12618 var id = null, d, t;
12620 var call = function(){
12621 var now = new Date().getTime();
12625 fn.apply(scope, args || []);
12629 * Cancels any pending timeout and queues a new one
12630 * @param {Number} delay The milliseconds to delay
12631 * @param {Function} newFn (optional) Overrides function passed to constructor
12632 * @param {Object} newScope (optional) Overrides scope passed to constructor
12633 * @param {Array} newArgs (optional) Overrides args passed to constructor
12635 this.delay = function(delay, newFn, newScope, newArgs){
12636 if(id && delay != d){
12640 t = new Date().getTime();
12642 scope = newScope || scope;
12643 args = newArgs || args;
12645 id = setInterval(call, d);
12650 * Cancel the last queued timeout
12652 this.cancel = function(){
12660 * Ext JS Library 1.1.1
12661 * Copyright(c) 2006-2007, Ext JS, LLC.
12663 * Originally Released Under LGPL - original licence link has changed is not relivant.
12666 * <script type="text/javascript">
12670 Roo.util.TaskRunner = function(interval){
12671 interval = interval || 10;
12672 var tasks = [], removeQueue = [];
12674 var running = false;
12676 var stopThread = function(){
12682 var startThread = function(){
12685 id = setInterval(runTasks, interval);
12689 var removeTask = function(task){
12690 removeQueue.push(task);
12696 var runTasks = function(){
12697 if(removeQueue.length > 0){
12698 for(var i = 0, len = removeQueue.length; i < len; i++){
12699 tasks.remove(removeQueue[i]);
12702 if(tasks.length < 1){
12707 var now = new Date().getTime();
12708 for(var i = 0, len = tasks.length; i < len; ++i){
12710 var itime = now - t.taskRunTime;
12711 if(t.interval <= itime){
12712 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12713 t.taskRunTime = now;
12714 if(rt === false || t.taskRunCount === t.repeat){
12719 if(t.duration && t.duration <= (now - t.taskStartTime)){
12726 * Queues a new task.
12727 * @param {Object} task
12729 this.start = function(task){
12731 task.taskStartTime = new Date().getTime();
12732 task.taskRunTime = 0;
12733 task.taskRunCount = 0;
12738 this.stop = function(task){
12743 this.stopAll = function(){
12745 for(var i = 0, len = tasks.length; i < len; i++){
12746 if(tasks[i].onStop){
12755 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12757 * Ext JS Library 1.1.1
12758 * Copyright(c) 2006-2007, Ext JS, LLC.
12760 * Originally Released Under LGPL - original licence link has changed is not relivant.
12763 * <script type="text/javascript">
12768 * @class Roo.util.MixedCollection
12769 * @extends Roo.util.Observable
12770 * A Collection class that maintains both numeric indexes and keys and exposes events.
12772 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12773 * collection (defaults to false)
12774 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12775 * and return the key value for that item. This is used when available to look up the key on items that
12776 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12777 * equivalent to providing an implementation for the {@link #getKey} method.
12779 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12787 * Fires when the collection is cleared.
12792 * Fires when an item is added to the collection.
12793 * @param {Number} index The index at which the item was added.
12794 * @param {Object} o The item added.
12795 * @param {String} key The key associated with the added item.
12800 * Fires when an item is replaced in the collection.
12801 * @param {String} key he key associated with the new added.
12802 * @param {Object} old The item being replaced.
12803 * @param {Object} new The new item.
12808 * Fires when an item is removed from the collection.
12809 * @param {Object} o The item being removed.
12810 * @param {String} key (optional) The key associated with the removed item.
12815 this.allowFunctions = allowFunctions === true;
12817 this.getKey = keyFn;
12819 Roo.util.MixedCollection.superclass.constructor.call(this);
12822 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12823 allowFunctions : false,
12826 * Adds an item to the collection.
12827 * @param {String} key The key to associate with the item
12828 * @param {Object} o The item to add.
12829 * @return {Object} The item added.
12831 add : function(key, o){
12832 if(arguments.length == 1){
12834 key = this.getKey(o);
12836 if(typeof key == "undefined" || key === null){
12838 this.items.push(o);
12839 this.keys.push(null);
12841 var old = this.map[key];
12843 return this.replace(key, o);
12846 this.items.push(o);
12848 this.keys.push(key);
12850 this.fireEvent("add", this.length-1, o, key);
12855 * MixedCollection has a generic way to fetch keys if you implement getKey.
12858 var mc = new Roo.util.MixedCollection();
12859 mc.add(someEl.dom.id, someEl);
12860 mc.add(otherEl.dom.id, otherEl);
12864 var mc = new Roo.util.MixedCollection();
12865 mc.getKey = function(el){
12871 // or via the constructor
12872 var mc = new Roo.util.MixedCollection(false, function(el){
12878 * @param o {Object} The item for which to find the key.
12879 * @return {Object} The key for the passed item.
12881 getKey : function(o){
12886 * Replaces an item in the collection.
12887 * @param {String} key The key associated with the item to replace, or the item to replace.
12888 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12889 * @return {Object} The new item.
12891 replace : function(key, o){
12892 if(arguments.length == 1){
12894 key = this.getKey(o);
12896 var old = this.item(key);
12897 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12898 return this.add(key, o);
12900 var index = this.indexOfKey(key);
12901 this.items[index] = o;
12903 this.fireEvent("replace", key, old, o);
12908 * Adds all elements of an Array or an Object to the collection.
12909 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12910 * an Array of values, each of which are added to the collection.
12912 addAll : function(objs){
12913 if(arguments.length > 1 || objs instanceof Array){
12914 var args = arguments.length > 1 ? arguments : objs;
12915 for(var i = 0, len = args.length; i < len; i++){
12919 for(var key in objs){
12920 if(this.allowFunctions || typeof objs[key] != "function"){
12921 this.add(key, objs[key]);
12928 * Executes the specified function once for every item in the collection, passing each
12929 * item as the first and only parameter. returning false from the function will stop the iteration.
12930 * @param {Function} fn The function to execute for each item.
12931 * @param {Object} scope (optional) The scope in which to execute the function.
12933 each : function(fn, scope){
12934 var items = [].concat(this.items); // each safe for removal
12935 for(var i = 0, len = items.length; i < len; i++){
12936 if(fn.call(scope || items[i], items[i], i, len) === false){
12943 * Executes the specified function once for every key in the collection, passing each
12944 * key, and its associated item as the first two parameters.
12945 * @param {Function} fn The function to execute for each item.
12946 * @param {Object} scope (optional) The scope in which to execute the function.
12948 eachKey : function(fn, scope){
12949 for(var i = 0, len = this.keys.length; i < len; i++){
12950 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12955 * Returns the first item in the collection which elicits a true return value from the
12956 * passed selection function.
12957 * @param {Function} fn The selection function to execute for each item.
12958 * @param {Object} scope (optional) The scope in which to execute the function.
12959 * @return {Object} The first item in the collection which returned true from the selection function.
12961 find : function(fn, scope){
12962 for(var i = 0, len = this.items.length; i < len; i++){
12963 if(fn.call(scope || window, this.items[i], this.keys[i])){
12964 return this.items[i];
12971 * Inserts an item at the specified index in the collection.
12972 * @param {Number} index The index to insert the item at.
12973 * @param {String} key The key to associate with the new item, or the item itself.
12974 * @param {Object} o (optional) If the second parameter was a key, the new item.
12975 * @return {Object} The item inserted.
12977 insert : function(index, key, o){
12978 if(arguments.length == 2){
12980 key = this.getKey(o);
12982 if(index >= this.length){
12983 return this.add(key, o);
12986 this.items.splice(index, 0, o);
12987 if(typeof key != "undefined" && key != null){
12990 this.keys.splice(index, 0, key);
12991 this.fireEvent("add", index, o, key);
12996 * Removed an item from the collection.
12997 * @param {Object} o The item to remove.
12998 * @return {Object} The item removed.
13000 remove : function(o){
13001 return this.removeAt(this.indexOf(o));
13005 * Remove an item from a specified index in the collection.
13006 * @param {Number} index The index within the collection of the item to remove.
13008 removeAt : function(index){
13009 if(index < this.length && index >= 0){
13011 var o = this.items[index];
13012 this.items.splice(index, 1);
13013 var key = this.keys[index];
13014 if(typeof key != "undefined"){
13015 delete this.map[key];
13017 this.keys.splice(index, 1);
13018 this.fireEvent("remove", o, key);
13023 * Removed an item associated with the passed key fom the collection.
13024 * @param {String} key The key of the item to remove.
13026 removeKey : function(key){
13027 return this.removeAt(this.indexOfKey(key));
13031 * Returns the number of items in the collection.
13032 * @return {Number} the number of items in the collection.
13034 getCount : function(){
13035 return this.length;
13039 * Returns index within the collection of the passed Object.
13040 * @param {Object} o The item to find the index of.
13041 * @return {Number} index of the item.
13043 indexOf : function(o){
13044 if(!this.items.indexOf){
13045 for(var i = 0, len = this.items.length; i < len; i++){
13046 if(this.items[i] == o) return i;
13050 return this.items.indexOf(o);
13055 * Returns index within the collection of the passed key.
13056 * @param {String} key The key to find the index of.
13057 * @return {Number} index of the key.
13059 indexOfKey : function(key){
13060 if(!this.keys.indexOf){
13061 for(var i = 0, len = this.keys.length; i < len; i++){
13062 if(this.keys[i] == key) return i;
13066 return this.keys.indexOf(key);
13071 * Returns the item associated with the passed key OR index. Key has priority over index.
13072 * @param {String/Number} key The key or index of the item.
13073 * @return {Object} The item associated with the passed key.
13075 item : function(key){
13076 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13077 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13081 * Returns the item at the specified index.
13082 * @param {Number} index The index of the item.
13085 itemAt : function(index){
13086 return this.items[index];
13090 * Returns the item associated with the passed key.
13091 * @param {String/Number} key The key of the item.
13092 * @return {Object} The item associated with the passed key.
13094 key : function(key){
13095 return this.map[key];
13099 * Returns true if the collection contains the passed Object as an item.
13100 * @param {Object} o The Object to look for in the collection.
13101 * @return {Boolean} True if the collection contains the Object as an item.
13103 contains : function(o){
13104 return this.indexOf(o) != -1;
13108 * Returns true if the collection contains the passed Object as a key.
13109 * @param {String} key The key to look for in the collection.
13110 * @return {Boolean} True if the collection contains the Object as a key.
13112 containsKey : function(key){
13113 return typeof this.map[key] != "undefined";
13117 * Removes all items from the collection.
13119 clear : function(){
13124 this.fireEvent("clear");
13128 * Returns the first item in the collection.
13129 * @return {Object} the first item in the collection..
13131 first : function(){
13132 return this.items[0];
13136 * Returns the last item in the collection.
13137 * @return {Object} the last item in the collection..
13140 return this.items[this.length-1];
13143 _sort : function(property, dir, fn){
13144 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13145 fn = fn || function(a, b){
13148 var c = [], k = this.keys, items = this.items;
13149 for(var i = 0, len = items.length; i < len; i++){
13150 c[c.length] = {key: k[i], value: items[i], index: i};
13152 c.sort(function(a, b){
13153 var v = fn(a[property], b[property]) * dsc;
13155 v = (a.index < b.index ? -1 : 1);
13159 for(var i = 0, len = c.length; i < len; i++){
13160 items[i] = c[i].value;
13163 this.fireEvent("sort", this);
13167 * Sorts this collection with the passed comparison function
13168 * @param {String} direction (optional) "ASC" or "DESC"
13169 * @param {Function} fn (optional) comparison function
13171 sort : function(dir, fn){
13172 this._sort("value", dir, fn);
13176 * Sorts this collection by keys
13177 * @param {String} direction (optional) "ASC" or "DESC"
13178 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13180 keySort : function(dir, fn){
13181 this._sort("key", dir, fn || function(a, b){
13182 return String(a).toUpperCase()-String(b).toUpperCase();
13187 * Returns a range of items in this collection
13188 * @param {Number} startIndex (optional) defaults to 0
13189 * @param {Number} endIndex (optional) default to the last item
13190 * @return {Array} An array of items
13192 getRange : function(start, end){
13193 var items = this.items;
13194 if(items.length < 1){
13197 start = start || 0;
13198 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13201 for(var i = start; i <= end; i++) {
13202 r[r.length] = items[i];
13205 for(var i = start; i >= end; i--) {
13206 r[r.length] = items[i];
13213 * Filter the <i>objects</i> in this collection by a specific property.
13214 * Returns a new collection that has been filtered.
13215 * @param {String} property A property on your objects
13216 * @param {String/RegExp} value Either string that the property values
13217 * should start with or a RegExp to test against the property
13218 * @return {MixedCollection} The new filtered collection
13220 filter : function(property, value){
13221 if(!value.exec){ // not a regex
13222 value = String(value);
13223 if(value.length == 0){
13224 return this.clone();
13226 value = new RegExp("^" + Roo.escapeRe(value), "i");
13228 return this.filterBy(function(o){
13229 return o && value.test(o[property]);
13234 * Filter by a function. * Returns a new collection that has been filtered.
13235 * The passed function will be called with each
13236 * object in the collection. If the function returns true, the value is included
13237 * otherwise it is filtered.
13238 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13239 * @param {Object} scope (optional) The scope of the function (defaults to this)
13240 * @return {MixedCollection} The new filtered collection
13242 filterBy : function(fn, scope){
13243 var r = new Roo.util.MixedCollection();
13244 r.getKey = this.getKey;
13245 var k = this.keys, it = this.items;
13246 for(var i = 0, len = it.length; i < len; i++){
13247 if(fn.call(scope||this, it[i], k[i])){
13248 r.add(k[i], it[i]);
13255 * Creates a duplicate of this collection
13256 * @return {MixedCollection}
13258 clone : function(){
13259 var r = new Roo.util.MixedCollection();
13260 var k = this.keys, it = this.items;
13261 for(var i = 0, len = it.length; i < len; i++){
13262 r.add(k[i], it[i]);
13264 r.getKey = this.getKey;
13269 * Returns the item associated with the passed key or index.
13271 * @param {String/Number} key The key or index of the item.
13272 * @return {Object} The item associated with the passed key.
13274 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13276 * Ext JS Library 1.1.1
13277 * Copyright(c) 2006-2007, Ext JS, LLC.
13279 * Originally Released Under LGPL - original licence link has changed is not relivant.
13282 * <script type="text/javascript">
13285 * @class Roo.util.JSON
13286 * Modified version of Douglas Crockford"s json.js that doesn"t
13287 * mess with the Object prototype
13288 * http://www.json.org/js.html
13291 Roo.util.JSON = new (function(){
13292 var useHasOwn = {}.hasOwnProperty ? true : false;
13294 // crashes Safari in some instances
13295 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13297 var pad = function(n) {
13298 return n < 10 ? "0" + n : n;
13311 var encodeString = function(s){
13312 if (/["\\\x00-\x1f]/.test(s)) {
13313 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13318 c = b.charCodeAt();
13320 Math.floor(c / 16).toString(16) +
13321 (c % 16).toString(16);
13324 return '"' + s + '"';
13327 var encodeArray = function(o){
13328 var a = ["["], b, i, l = o.length, v;
13329 for (i = 0; i < l; i += 1) {
13331 switch (typeof v) {
13340 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13348 var encodeDate = function(o){
13349 return '"' + o.getFullYear() + "-" +
13350 pad(o.getMonth() + 1) + "-" +
13351 pad(o.getDate()) + "T" +
13352 pad(o.getHours()) + ":" +
13353 pad(o.getMinutes()) + ":" +
13354 pad(o.getSeconds()) + '"';
13358 * Encodes an Object, Array or other value
13359 * @param {Mixed} o The variable to encode
13360 * @return {String} The JSON string
13362 this.encode = function(o)
13364 // should this be extended to fully wrap stringify..
13366 if(typeof o == "undefined" || o === null){
13368 }else if(o instanceof Array){
13369 return encodeArray(o);
13370 }else if(o instanceof Date){
13371 return encodeDate(o);
13372 }else if(typeof o == "string"){
13373 return encodeString(o);
13374 }else if(typeof o == "number"){
13375 return isFinite(o) ? String(o) : "null";
13376 }else if(typeof o == "boolean"){
13379 var a = ["{"], b, i, v;
13381 if(!useHasOwn || o.hasOwnProperty(i)) {
13383 switch (typeof v) {
13392 a.push(this.encode(i), ":",
13393 v === null ? "null" : this.encode(v));
13404 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13405 * @param {String} json The JSON string
13406 * @return {Object} The resulting object
13408 this.decode = function(json){
13410 return /** eval:var:json */ eval("(" + json + ')');
13414 * Shorthand for {@link Roo.util.JSON#encode}
13415 * @member Roo encode
13417 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13419 * Shorthand for {@link Roo.util.JSON#decode}
13420 * @member Roo decode
13422 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13425 * Ext JS Library 1.1.1
13426 * Copyright(c) 2006-2007, Ext JS, LLC.
13428 * Originally Released Under LGPL - original licence link has changed is not relivant.
13431 * <script type="text/javascript">
13435 * @class Roo.util.Format
13436 * Reusable data formatting functions
13439 Roo.util.Format = function(){
13440 var trimRe = /^\s+|\s+$/g;
13443 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13444 * @param {String} value The string to truncate
13445 * @param {Number} length The maximum length to allow before truncating
13446 * @return {String} The converted text
13448 ellipsis : function(value, len){
13449 if(value && value.length > len){
13450 return value.substr(0, len-3)+"...";
13456 * Checks a reference and converts it to empty string if it is undefined
13457 * @param {Mixed} value Reference to check
13458 * @return {Mixed} Empty string if converted, otherwise the original value
13460 undef : function(value){
13461 return typeof value != "undefined" ? value : "";
13465 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13466 * @param {String} value The string to encode
13467 * @return {String} The encoded text
13469 htmlEncode : function(value){
13470 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13474 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13475 * @param {String} value The string to decode
13476 * @return {String} The decoded text
13478 htmlDecode : function(value){
13479 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13483 * Trims any whitespace from either side of a string
13484 * @param {String} value The text to trim
13485 * @return {String} The trimmed text
13487 trim : function(value){
13488 return String(value).replace(trimRe, "");
13492 * Returns a substring from within an original string
13493 * @param {String} value The original text
13494 * @param {Number} start The start index of the substring
13495 * @param {Number} length The length of the substring
13496 * @return {String} The substring
13498 substr : function(value, start, length){
13499 return String(value).substr(start, length);
13503 * Converts a string to all lower case letters
13504 * @param {String} value The text to convert
13505 * @return {String} The converted text
13507 lowercase : function(value){
13508 return String(value).toLowerCase();
13512 * Converts a string to all upper case letters
13513 * @param {String} value The text to convert
13514 * @return {String} The converted text
13516 uppercase : function(value){
13517 return String(value).toUpperCase();
13521 * Converts the first character only of a string to upper case
13522 * @param {String} value The text to convert
13523 * @return {String} The converted text
13525 capitalize : function(value){
13526 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13530 call : function(value, fn){
13531 if(arguments.length > 2){
13532 var args = Array.prototype.slice.call(arguments, 2);
13533 args.unshift(value);
13535 return /** eval:var:value */ eval(fn).apply(window, args);
13537 /** eval:var:value */
13538 return /** eval:var:value */ eval(fn).call(window, value);
13544 * safer version of Math.toFixed..??/
13545 * @param {Number/String} value The numeric value to format
13546 * @param {Number/String} value Decimal places
13547 * @return {String} The formatted currency string
13549 toFixed : function(v, n)
13551 // why not use to fixed - precision is buggered???
13553 return Math.round(v-0);
13555 var fact = Math.pow(10,n+1);
13556 v = (Math.round((v-0)*fact))/fact;
13557 var z = (''+fact).substring(2);
13558 if (v == Math.floor(v)) {
13559 return Math.floor(v) + '.' + z;
13562 // now just padd decimals..
13563 var ps = String(v).split('.');
13564 var fd = (ps[1] + z);
13565 var r = fd.substring(0,n);
13566 var rm = fd.substring(n);
13568 return ps[0] + '.' + r;
13570 r*=1; // turn it into a number;
13572 if (String(r).length != n) {
13575 r = String(r).substring(1); // chop the end off.
13578 return ps[0] + '.' + r;
13583 * Format a number as US currency
13584 * @param {Number/String} value The numeric value to format
13585 * @return {String} The formatted currency string
13587 usMoney : function(v){
13588 return '$' + Roo.util.Format.number(v);
13593 * eventually this should probably emulate php's number_format
13594 * @param {Number/String} value The numeric value to format
13595 * @param {Number} decimals number of decimal places
13596 * @return {String} The formatted currency string
13598 number : function(v,decimals)
13600 // multiply and round.
13601 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13602 var mul = Math.pow(10, decimals);
13603 var zero = String(mul).substring(1);
13604 v = (Math.round((v-0)*mul))/mul;
13606 // if it's '0' number.. then
13608 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13610 var ps = v.split('.');
13614 var r = /(\d+)(\d{3})/;
13616 while (r.test(whole)) {
13617 whole = whole.replace(r, '$1' + ',' + '$2');
13623 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13624 // does not have decimals
13625 (decimals ? ('.' + zero) : '');
13628 return whole + sub ;
13632 * Parse a value into a formatted date using the specified format pattern.
13633 * @param {Mixed} value The value to format
13634 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13635 * @return {String} The formatted date string
13637 date : function(v, format){
13641 if(!(v instanceof Date)){
13642 v = new Date(Date.parse(v));
13644 return v.dateFormat(format || "m/d/Y");
13648 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13649 * @param {String} format Any valid date format string
13650 * @return {Function} The date formatting function
13652 dateRenderer : function(format){
13653 return function(v){
13654 return Roo.util.Format.date(v, format);
13659 stripTagsRE : /<\/?[^>]+>/gi,
13662 * Strips all HTML tags
13663 * @param {Mixed} value The text from which to strip tags
13664 * @return {String} The stripped text
13666 stripTags : function(v){
13667 return !v ? v : String(v).replace(this.stripTagsRE, "");
13672 * Ext JS Library 1.1.1
13673 * Copyright(c) 2006-2007, Ext JS, LLC.
13675 * Originally Released Under LGPL - original licence link has changed is not relivant.
13678 * <script type="text/javascript">
13685 * @class Roo.MasterTemplate
13686 * @extends Roo.Template
13687 * Provides a template that can have child templates. The syntax is:
13689 var t = new Roo.MasterTemplate(
13690 '<select name="{name}">',
13691 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13694 t.add('options', {value: 'foo', text: 'bar'});
13695 // or you can add multiple child elements in one shot
13696 t.addAll('options', [
13697 {value: 'foo', text: 'bar'},
13698 {value: 'foo2', text: 'bar2'},
13699 {value: 'foo3', text: 'bar3'}
13701 // then append, applying the master template values
13702 t.append('my-form', {name: 'my-select'});
13704 * A name attribute for the child template is not required if you have only one child
13705 * template or you want to refer to them by index.
13707 Roo.MasterTemplate = function(){
13708 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13709 this.originalHtml = this.html;
13711 var m, re = this.subTemplateRe;
13714 while(m = re.exec(this.html)){
13715 var name = m[1], content = m[2];
13720 tpl : new Roo.Template(content)
13723 st[name] = st[subIndex];
13725 st[subIndex].tpl.compile();
13726 st[subIndex].tpl.call = this.call.createDelegate(this);
13729 this.subCount = subIndex;
13732 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13734 * The regular expression used to match sub templates
13738 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13741 * Applies the passed values to a child template.
13742 * @param {String/Number} name (optional) The name or index of the child template
13743 * @param {Array/Object} values The values to be applied to the template
13744 * @return {MasterTemplate} this
13746 add : function(name, values){
13747 if(arguments.length == 1){
13748 values = arguments[0];
13751 var s = this.subs[name];
13752 s.buffer[s.buffer.length] = s.tpl.apply(values);
13757 * Applies all the passed values to a child template.
13758 * @param {String/Number} name (optional) The name or index of the child template
13759 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13760 * @param {Boolean} reset (optional) True to reset the template first
13761 * @return {MasterTemplate} this
13763 fill : function(name, values, reset){
13765 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13773 for(var i = 0, len = values.length; i < len; i++){
13774 this.add(name, values[i]);
13780 * Resets the template for reuse
13781 * @return {MasterTemplate} this
13783 reset : function(){
13785 for(var i = 0; i < this.subCount; i++){
13791 applyTemplate : function(values){
13793 var replaceIndex = -1;
13794 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13795 return s[++replaceIndex].buffer.join("");
13797 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13800 apply : function(){
13801 return this.applyTemplate.apply(this, arguments);
13804 compile : function(){return this;}
13808 * Alias for fill().
13811 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13813 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13814 * var tpl = Roo.MasterTemplate.from('element-id');
13815 * @param {String/HTMLElement} el
13816 * @param {Object} config
13819 Roo.MasterTemplate.from = function(el, config){
13820 el = Roo.getDom(el);
13821 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13824 * Ext JS Library 1.1.1
13825 * Copyright(c) 2006-2007, Ext JS, LLC.
13827 * Originally Released Under LGPL - original licence link has changed is not relivant.
13830 * <script type="text/javascript">
13835 * @class Roo.util.CSS
13836 * Utility class for manipulating CSS rules
13839 Roo.util.CSS = function(){
13841 var doc = document;
13843 var camelRe = /(-[a-z])/gi;
13844 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13848 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13849 * tag and appended to the HEAD of the document.
13850 * @param {String|Object} cssText The text containing the css rules
13851 * @param {String} id An id to add to the stylesheet for later removal
13852 * @return {StyleSheet}
13854 createStyleSheet : function(cssText, id){
13856 var head = doc.getElementsByTagName("head")[0];
13857 var nrules = doc.createElement("style");
13858 nrules.setAttribute("type", "text/css");
13860 nrules.setAttribute("id", id);
13862 if (typeof(cssText) != 'string') {
13863 // support object maps..
13864 // not sure if this a good idea..
13865 // perhaps it should be merged with the general css handling
13866 // and handle js style props.
13867 var cssTextNew = [];
13868 for(var n in cssText) {
13870 for(var k in cssText[n]) {
13871 citems.push( k + ' : ' +cssText[n][k] + ';' );
13873 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13876 cssText = cssTextNew.join("\n");
13882 head.appendChild(nrules);
13883 ss = nrules.styleSheet;
13884 ss.cssText = cssText;
13887 nrules.appendChild(doc.createTextNode(cssText));
13889 nrules.cssText = cssText;
13891 head.appendChild(nrules);
13892 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13894 this.cacheStyleSheet(ss);
13899 * Removes a style or link tag by id
13900 * @param {String} id The id of the tag
13902 removeStyleSheet : function(id){
13903 var existing = doc.getElementById(id);
13905 existing.parentNode.removeChild(existing);
13910 * Dynamically swaps an existing stylesheet reference for a new one
13911 * @param {String} id The id of an existing link tag to remove
13912 * @param {String} url The href of the new stylesheet to include
13914 swapStyleSheet : function(id, url){
13915 this.removeStyleSheet(id);
13916 var ss = doc.createElement("link");
13917 ss.setAttribute("rel", "stylesheet");
13918 ss.setAttribute("type", "text/css");
13919 ss.setAttribute("id", id);
13920 ss.setAttribute("href", url);
13921 doc.getElementsByTagName("head")[0].appendChild(ss);
13925 * Refresh the rule cache if you have dynamically added stylesheets
13926 * @return {Object} An object (hash) of rules indexed by selector
13928 refreshCache : function(){
13929 return this.getRules(true);
13933 cacheStyleSheet : function(stylesheet){
13937 try{// try catch for cross domain access issue
13938 var ssRules = stylesheet.cssRules || stylesheet.rules;
13939 for(var j = ssRules.length-1; j >= 0; --j){
13940 rules[ssRules[j].selectorText] = ssRules[j];
13946 * Gets all css rules for the document
13947 * @param {Boolean} refreshCache true to refresh the internal cache
13948 * @return {Object} An object (hash) of rules indexed by selector
13950 getRules : function(refreshCache){
13951 if(rules == null || refreshCache){
13953 var ds = doc.styleSheets;
13954 for(var i =0, len = ds.length; i < len; i++){
13956 this.cacheStyleSheet(ds[i]);
13964 * Gets an an individual CSS rule by selector(s)
13965 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13966 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13967 * @return {CSSRule} The CSS rule or null if one is not found
13969 getRule : function(selector, refreshCache){
13970 var rs = this.getRules(refreshCache);
13971 if(!(selector instanceof Array)){
13972 return rs[selector];
13974 for(var i = 0; i < selector.length; i++){
13975 if(rs[selector[i]]){
13976 return rs[selector[i]];
13984 * Updates a rule property
13985 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13986 * @param {String} property The css property
13987 * @param {String} value The new value for the property
13988 * @return {Boolean} true If a rule was found and updated
13990 updateRule : function(selector, property, value){
13991 if(!(selector instanceof Array)){
13992 var rule = this.getRule(selector);
13994 rule.style[property.replace(camelRe, camelFn)] = value;
13998 for(var i = 0; i < selector.length; i++){
13999 if(this.updateRule(selector[i], property, value)){
14009 * Ext JS Library 1.1.1
14010 * Copyright(c) 2006-2007, Ext JS, LLC.
14012 * Originally Released Under LGPL - original licence link has changed is not relivant.
14015 * <script type="text/javascript">
14021 * @class Roo.util.ClickRepeater
14022 * @extends Roo.util.Observable
14024 * A wrapper class which can be applied to any element. Fires a "click" event while the
14025 * mouse is pressed. The interval between firings may be specified in the config but
14026 * defaults to 10 milliseconds.
14028 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14030 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14031 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14032 * Similar to an autorepeat key delay.
14033 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14034 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14035 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14036 * "interval" and "delay" are ignored. "immediate" is honored.
14037 * @cfg {Boolean} preventDefault True to prevent the default click event
14038 * @cfg {Boolean} stopDefault True to stop the default click event
14041 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14042 * 2007-02-02 jvs Renamed to ClickRepeater
14043 * 2007-02-03 jvs Modifications for FF Mac and Safari
14046 * @param {String/HTMLElement/Element} el The element to listen on
14047 * @param {Object} config
14049 Roo.util.ClickRepeater = function(el, config)
14051 this.el = Roo.get(el);
14052 this.el.unselectable();
14054 Roo.apply(this, config);
14059 * Fires when the mouse button is depressed.
14060 * @param {Roo.util.ClickRepeater} this
14062 "mousedown" : true,
14065 * Fires on a specified interval during the time the element is pressed.
14066 * @param {Roo.util.ClickRepeater} this
14071 * Fires when the mouse key is released.
14072 * @param {Roo.util.ClickRepeater} this
14077 this.el.on("mousedown", this.handleMouseDown, this);
14078 if(this.preventDefault || this.stopDefault){
14079 this.el.on("click", function(e){
14080 if(this.preventDefault){
14081 e.preventDefault();
14083 if(this.stopDefault){
14089 // allow inline handler
14091 this.on("click", this.handler, this.scope || this);
14094 Roo.util.ClickRepeater.superclass.constructor.call(this);
14097 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14100 preventDefault : true,
14101 stopDefault : false,
14105 handleMouseDown : function(){
14106 clearTimeout(this.timer);
14108 if(this.pressClass){
14109 this.el.addClass(this.pressClass);
14111 this.mousedownTime = new Date();
14113 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14114 this.el.on("mouseout", this.handleMouseOut, this);
14116 this.fireEvent("mousedown", this);
14117 this.fireEvent("click", this);
14119 this.timer = this.click.defer(this.delay || this.interval, this);
14123 click : function(){
14124 this.fireEvent("click", this);
14125 this.timer = this.click.defer(this.getInterval(), this);
14129 getInterval: function(){
14130 if(!this.accelerate){
14131 return this.interval;
14133 var pressTime = this.mousedownTime.getElapsed();
14134 if(pressTime < 500){
14136 }else if(pressTime < 1700){
14138 }else if(pressTime < 2600){
14140 }else if(pressTime < 3500){
14142 }else if(pressTime < 4400){
14144 }else if(pressTime < 5300){
14146 }else if(pressTime < 6200){
14154 handleMouseOut : function(){
14155 clearTimeout(this.timer);
14156 if(this.pressClass){
14157 this.el.removeClass(this.pressClass);
14159 this.el.on("mouseover", this.handleMouseReturn, this);
14163 handleMouseReturn : function(){
14164 this.el.un("mouseover", this.handleMouseReturn);
14165 if(this.pressClass){
14166 this.el.addClass(this.pressClass);
14172 handleMouseUp : function(){
14173 clearTimeout(this.timer);
14174 this.el.un("mouseover", this.handleMouseReturn);
14175 this.el.un("mouseout", this.handleMouseOut);
14176 Roo.get(document).un("mouseup", this.handleMouseUp);
14177 this.el.removeClass(this.pressClass);
14178 this.fireEvent("mouseup", this);
14182 * Ext JS Library 1.1.1
14183 * Copyright(c) 2006-2007, Ext JS, LLC.
14185 * Originally Released Under LGPL - original licence link has changed is not relivant.
14188 * <script type="text/javascript">
14193 * @class Roo.KeyNav
14194 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14195 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14196 * way to implement custom navigation schemes for any UI component.</p>
14197 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14198 * pageUp, pageDown, del, home, end. Usage:</p>
14200 var nav = new Roo.KeyNav("my-element", {
14201 "left" : function(e){
14202 this.moveLeft(e.ctrlKey);
14204 "right" : function(e){
14205 this.moveRight(e.ctrlKey);
14207 "enter" : function(e){
14214 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14215 * @param {Object} config The config
14217 Roo.KeyNav = function(el, config){
14218 this.el = Roo.get(el);
14219 Roo.apply(this, config);
14220 if(!this.disabled){
14221 this.disabled = true;
14226 Roo.KeyNav.prototype = {
14228 * @cfg {Boolean} disabled
14229 * True to disable this KeyNav instance (defaults to false)
14233 * @cfg {String} defaultEventAction
14234 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14235 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14236 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14238 defaultEventAction: "stopEvent",
14240 * @cfg {Boolean} forceKeyDown
14241 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14242 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14243 * handle keydown instead of keypress.
14245 forceKeyDown : false,
14248 prepareEvent : function(e){
14249 var k = e.getKey();
14250 var h = this.keyToHandler[k];
14251 //if(h && this[h]){
14252 // e.stopPropagation();
14254 if(Roo.isSafari && h && k >= 37 && k <= 40){
14260 relay : function(e){
14261 var k = e.getKey();
14262 var h = this.keyToHandler[k];
14264 if(this.doRelay(e, this[h], h) !== true){
14265 e[this.defaultEventAction]();
14271 doRelay : function(e, h, hname){
14272 return h.call(this.scope || this, e);
14275 // possible handlers
14289 // quick lookup hash
14306 * Enable this KeyNav
14308 enable: function(){
14310 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14311 // the EventObject will normalize Safari automatically
14312 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14313 this.el.on("keydown", this.relay, this);
14315 this.el.on("keydown", this.prepareEvent, this);
14316 this.el.on("keypress", this.relay, this);
14318 this.disabled = false;
14323 * Disable this KeyNav
14325 disable: function(){
14326 if(!this.disabled){
14327 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14328 this.el.un("keydown", this.relay);
14330 this.el.un("keydown", this.prepareEvent);
14331 this.el.un("keypress", this.relay);
14333 this.disabled = true;
14338 * Ext JS Library 1.1.1
14339 * Copyright(c) 2006-2007, Ext JS, LLC.
14341 * Originally Released Under LGPL - original licence link has changed is not relivant.
14344 * <script type="text/javascript">
14349 * @class Roo.KeyMap
14350 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14351 * The constructor accepts the same config object as defined by {@link #addBinding}.
14352 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14353 * combination it will call the function with this signature (if the match is a multi-key
14354 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14355 * A KeyMap can also handle a string representation of keys.<br />
14358 // map one key by key code
14359 var map = new Roo.KeyMap("my-element", {
14360 key: 13, // or Roo.EventObject.ENTER
14365 // map multiple keys to one action by string
14366 var map = new Roo.KeyMap("my-element", {
14372 // map multiple keys to multiple actions by strings and array of codes
14373 var map = new Roo.KeyMap("my-element", [
14376 fn: function(){ alert("Return was pressed"); }
14379 fn: function(){ alert('a, b or c was pressed'); }
14384 fn: function(){ alert('Control + shift + tab was pressed.'); }
14388 * <b>Note: A KeyMap starts enabled</b>
14390 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14391 * @param {Object} config The config (see {@link #addBinding})
14392 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14394 Roo.KeyMap = function(el, config, eventName){
14395 this.el = Roo.get(el);
14396 this.eventName = eventName || "keydown";
14397 this.bindings = [];
14399 this.addBinding(config);
14404 Roo.KeyMap.prototype = {
14406 * True to stop the event from bubbling and prevent the default browser action if the
14407 * key was handled by the KeyMap (defaults to false)
14413 * Add a new binding to this KeyMap. The following config object properties are supported:
14415 Property Type Description
14416 ---------- --------------- ----------------------------------------------------------------------
14417 key String/Array A single keycode or an array of keycodes to handle
14418 shift Boolean True to handle key only when shift is pressed (defaults to false)
14419 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14420 alt Boolean True to handle key only when alt is pressed (defaults to false)
14421 fn Function The function to call when KeyMap finds the expected key combination
14422 scope Object The scope of the callback function
14428 var map = new Roo.KeyMap(document, {
14429 key: Roo.EventObject.ENTER,
14434 //Add a new binding to the existing KeyMap later
14442 * @param {Object/Array} config A single KeyMap config or an array of configs
14444 addBinding : function(config){
14445 if(config instanceof Array){
14446 for(var i = 0, len = config.length; i < len; i++){
14447 this.addBinding(config[i]);
14451 var keyCode = config.key,
14452 shift = config.shift,
14453 ctrl = config.ctrl,
14456 scope = config.scope;
14457 if(typeof keyCode == "string"){
14459 var keyString = keyCode.toUpperCase();
14460 for(var j = 0, len = keyString.length; j < len; j++){
14461 ks.push(keyString.charCodeAt(j));
14465 var keyArray = keyCode instanceof Array;
14466 var handler = function(e){
14467 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14468 var k = e.getKey();
14470 for(var i = 0, len = keyCode.length; i < len; i++){
14471 if(keyCode[i] == k){
14472 if(this.stopEvent){
14475 fn.call(scope || window, k, e);
14481 if(this.stopEvent){
14484 fn.call(scope || window, k, e);
14489 this.bindings.push(handler);
14493 * Shorthand for adding a single key listener
14494 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14495 * following options:
14496 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14497 * @param {Function} fn The function to call
14498 * @param {Object} scope (optional) The scope of the function
14500 on : function(key, fn, scope){
14501 var keyCode, shift, ctrl, alt;
14502 if(typeof key == "object" && !(key instanceof Array)){
14521 handleKeyDown : function(e){
14522 if(this.enabled){ //just in case
14523 var b = this.bindings;
14524 for(var i = 0, len = b.length; i < len; i++){
14525 b[i].call(this, e);
14531 * Returns true if this KeyMap is enabled
14532 * @return {Boolean}
14534 isEnabled : function(){
14535 return this.enabled;
14539 * Enables this KeyMap
14541 enable: function(){
14543 this.el.on(this.eventName, this.handleKeyDown, this);
14544 this.enabled = true;
14549 * Disable this KeyMap
14551 disable: function(){
14553 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14554 this.enabled = false;
14559 * Ext JS Library 1.1.1
14560 * Copyright(c) 2006-2007, Ext JS, LLC.
14562 * Originally Released Under LGPL - original licence link has changed is not relivant.
14565 * <script type="text/javascript">
14570 * @class Roo.util.TextMetrics
14571 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14572 * wide, in pixels, a given block of text will be.
14575 Roo.util.TextMetrics = function(){
14579 * Measures the size of the specified text
14580 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14581 * that can affect the size of the rendered text
14582 * @param {String} text The text to measure
14583 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14584 * in order to accurately measure the text height
14585 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14587 measure : function(el, text, fixedWidth){
14589 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14592 shared.setFixedWidth(fixedWidth || 'auto');
14593 return shared.getSize(text);
14597 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14598 * the overhead of multiple calls to initialize the style properties on each measurement.
14599 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14600 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14601 * in order to accurately measure the text height
14602 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14604 createInstance : function(el, fixedWidth){
14605 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14612 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14613 var ml = new Roo.Element(document.createElement('div'));
14614 document.body.appendChild(ml.dom);
14615 ml.position('absolute');
14616 ml.setLeftTop(-1000, -1000);
14620 ml.setWidth(fixedWidth);
14625 * Returns the size of the specified text based on the internal element's style and width properties
14626 * @memberOf Roo.util.TextMetrics.Instance#
14627 * @param {String} text The text to measure
14628 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14630 getSize : function(text){
14632 var s = ml.getSize();
14638 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14639 * that can affect the size of the rendered text
14640 * @memberOf Roo.util.TextMetrics.Instance#
14641 * @param {String/HTMLElement} el The element, dom node or id
14643 bind : function(el){
14645 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14650 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14651 * to set a fixed width in order to accurately measure the text height.
14652 * @memberOf Roo.util.TextMetrics.Instance#
14653 * @param {Number} width The width to set on the element
14655 setFixedWidth : function(width){
14656 ml.setWidth(width);
14660 * Returns the measured width of the specified text
14661 * @memberOf Roo.util.TextMetrics.Instance#
14662 * @param {String} text The text to measure
14663 * @return {Number} width The width in pixels
14665 getWidth : function(text){
14666 ml.dom.style.width = 'auto';
14667 return this.getSize(text).width;
14671 * Returns the measured height of the specified text. For multiline text, be sure to call
14672 * {@link #setFixedWidth} if necessary.
14673 * @memberOf Roo.util.TextMetrics.Instance#
14674 * @param {String} text The text to measure
14675 * @return {Number} height The height in pixels
14677 getHeight : function(text){
14678 return this.getSize(text).height;
14682 instance.bind(bindTo);
14687 // backwards compat
14688 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14690 * Ext JS Library 1.1.1
14691 * Copyright(c) 2006-2007, Ext JS, LLC.
14693 * Originally Released Under LGPL - original licence link has changed is not relivant.
14696 * <script type="text/javascript">
14700 * @class Roo.state.Provider
14701 * Abstract base class for state provider implementations. This class provides methods
14702 * for encoding and decoding <b>typed</b> variables including dates and defines the
14703 * Provider interface.
14705 Roo.state.Provider = function(){
14707 * @event statechange
14708 * Fires when a state change occurs.
14709 * @param {Provider} this This state provider
14710 * @param {String} key The state key which was changed
14711 * @param {String} value The encoded value for the state
14714 "statechange": true
14717 Roo.state.Provider.superclass.constructor.call(this);
14719 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14721 * Returns the current value for a key
14722 * @param {String} name The key name
14723 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14724 * @return {Mixed} The state data
14726 get : function(name, defaultValue){
14727 return typeof this.state[name] == "undefined" ?
14728 defaultValue : this.state[name];
14732 * Clears a value from the state
14733 * @param {String} name The key name
14735 clear : function(name){
14736 delete this.state[name];
14737 this.fireEvent("statechange", this, name, null);
14741 * Sets the value for a key
14742 * @param {String} name The key name
14743 * @param {Mixed} value The value to set
14745 set : function(name, value){
14746 this.state[name] = value;
14747 this.fireEvent("statechange", this, name, value);
14751 * Decodes a string previously encoded with {@link #encodeValue}.
14752 * @param {String} value The value to decode
14753 * @return {Mixed} The decoded value
14755 decodeValue : function(cookie){
14756 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14757 var matches = re.exec(unescape(cookie));
14758 if(!matches || !matches[1]) return; // non state cookie
14759 var type = matches[1];
14760 var v = matches[2];
14763 return parseFloat(v);
14765 return new Date(Date.parse(v));
14770 var values = v.split("^");
14771 for(var i = 0, len = values.length; i < len; i++){
14772 all.push(this.decodeValue(values[i]));
14777 var values = v.split("^");
14778 for(var i = 0, len = values.length; i < len; i++){
14779 var kv = values[i].split("=");
14780 all[kv[0]] = this.decodeValue(kv[1]);
14789 * Encodes a value including type information. Decode with {@link #decodeValue}.
14790 * @param {Mixed} value The value to encode
14791 * @return {String} The encoded value
14793 encodeValue : function(v){
14795 if(typeof v == "number"){
14797 }else if(typeof v == "boolean"){
14798 enc = "b:" + (v ? "1" : "0");
14799 }else if(v instanceof Date){
14800 enc = "d:" + v.toGMTString();
14801 }else if(v instanceof Array){
14803 for(var i = 0, len = v.length; i < len; i++){
14804 flat += this.encodeValue(v[i]);
14805 if(i != len-1) flat += "^";
14808 }else if(typeof v == "object"){
14811 if(typeof v[key] != "function"){
14812 flat += key + "=" + this.encodeValue(v[key]) + "^";
14815 enc = "o:" + flat.substring(0, flat.length-1);
14819 return escape(enc);
14825 * Ext JS Library 1.1.1
14826 * Copyright(c) 2006-2007, Ext JS, LLC.
14828 * Originally Released Under LGPL - original licence link has changed is not relivant.
14831 * <script type="text/javascript">
14834 * @class Roo.state.Manager
14835 * This is the global state manager. By default all components that are "state aware" check this class
14836 * for state information if you don't pass them a custom state provider. In order for this class
14837 * to be useful, it must be initialized with a provider when your application initializes.
14839 // in your initialization function
14841 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14843 // supposed you have a {@link Roo.BorderLayout}
14844 var layout = new Roo.BorderLayout(...);
14845 layout.restoreState();
14846 // or a {Roo.BasicDialog}
14847 var dialog = new Roo.BasicDialog(...);
14848 dialog.restoreState();
14852 Roo.state.Manager = function(){
14853 var provider = new Roo.state.Provider();
14857 * Configures the default state provider for your application
14858 * @param {Provider} stateProvider The state provider to set
14860 setProvider : function(stateProvider){
14861 provider = stateProvider;
14865 * Returns the current value for a key
14866 * @param {String} name The key name
14867 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14868 * @return {Mixed} The state data
14870 get : function(key, defaultValue){
14871 return provider.get(key, defaultValue);
14875 * Sets the value for a key
14876 * @param {String} name The key name
14877 * @param {Mixed} value The state data
14879 set : function(key, value){
14880 provider.set(key, value);
14884 * Clears a value from the state
14885 * @param {String} name The key name
14887 clear : function(key){
14888 provider.clear(key);
14892 * Gets the currently configured state provider
14893 * @return {Provider} The state provider
14895 getProvider : function(){
14902 * Ext JS Library 1.1.1
14903 * Copyright(c) 2006-2007, Ext JS, LLC.
14905 * Originally Released Under LGPL - original licence link has changed is not relivant.
14908 * <script type="text/javascript">
14911 * @class Roo.state.CookieProvider
14912 * @extends Roo.state.Provider
14913 * The default Provider implementation which saves state via cookies.
14916 var cp = new Roo.state.CookieProvider({
14918 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14919 domain: "roojs.com"
14921 Roo.state.Manager.setProvider(cp);
14923 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14924 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14925 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14926 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14927 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14928 * domain the page is running on including the 'www' like 'www.roojs.com')
14929 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14931 * Create a new CookieProvider
14932 * @param {Object} config The configuration object
14934 Roo.state.CookieProvider = function(config){
14935 Roo.state.CookieProvider.superclass.constructor.call(this);
14937 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14938 this.domain = null;
14939 this.secure = false;
14940 Roo.apply(this, config);
14941 this.state = this.readCookies();
14944 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14946 set : function(name, value){
14947 if(typeof value == "undefined" || value === null){
14951 this.setCookie(name, value);
14952 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14956 clear : function(name){
14957 this.clearCookie(name);
14958 Roo.state.CookieProvider.superclass.clear.call(this, name);
14962 readCookies : function(){
14964 var c = document.cookie + ";";
14965 var re = /\s?(.*?)=(.*?);/g;
14967 while((matches = re.exec(c)) != null){
14968 var name = matches[1];
14969 var value = matches[2];
14970 if(name && name.substring(0,3) == "ys-"){
14971 cookies[name.substr(3)] = this.decodeValue(value);
14978 setCookie : function(name, value){
14979 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14980 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14981 ((this.path == null) ? "" : ("; path=" + this.path)) +
14982 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14983 ((this.secure == true) ? "; secure" : "");
14987 clearCookie : function(name){
14988 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14989 ((this.path == null) ? "" : ("; path=" + this.path)) +
14990 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14991 ((this.secure == true) ? "; secure" : "");
14995 * Ext JS Library 1.1.1
14996 * Copyright(c) 2006-2007, Ext JS, LLC.
14998 * Originally Released Under LGPL - original licence link has changed is not relivant.
15001 * <script type="text/javascript">
15007 * These classes are derivatives of the similarly named classes in the YUI Library.
15008 * The original license:
15009 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
15010 * Code licensed under the BSD License:
15011 * http://developer.yahoo.net/yui/license.txt
15016 var Event=Roo.EventManager;
15017 var Dom=Roo.lib.Dom;
15020 * @class Roo.dd.DragDrop
15021 * @extends Roo.util.Observable
15022 * Defines the interface and base operation of items that that can be
15023 * dragged or can be drop targets. It was designed to be extended, overriding
15024 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
15025 * Up to three html elements can be associated with a DragDrop instance:
15027 * <li>linked element: the element that is passed into the constructor.
15028 * This is the element which defines the boundaries for interaction with
15029 * other DragDrop objects.</li>
15030 * <li>handle element(s): The drag operation only occurs if the element that
15031 * was clicked matches a handle element. By default this is the linked
15032 * element, but there are times that you will want only a portion of the
15033 * linked element to initiate the drag operation, and the setHandleElId()
15034 * method provides a way to define this.</li>
15035 * <li>drag element: this represents the element that would be moved along
15036 * with the cursor during a drag operation. By default, this is the linked
15037 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
15038 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
15041 * This class should not be instantiated until the onload event to ensure that
15042 * the associated elements are available.
15043 * The following would define a DragDrop obj that would interact with any
15044 * other DragDrop obj in the "group1" group:
15046 * dd = new Roo.dd.DragDrop("div1", "group1");
15048 * Since none of the event handlers have been implemented, nothing would
15049 * actually happen if you were to run the code above. Normally you would
15050 * override this class or one of the default implementations, but you can
15051 * also override the methods you want on an instance of the class...
15053 * dd.onDragDrop = function(e, id) {
15054 * alert("dd was dropped on " + id);
15058 * @param {String} id of the element that is linked to this instance
15059 * @param {String} sGroup the group of related DragDrop objects
15060 * @param {object} config an object containing configurable attributes
15061 * Valid properties for DragDrop:
15062 * padding, isTarget, maintainOffset, primaryButtonOnly
15064 Roo.dd.DragDrop = function(id, sGroup, config) {
15066 this.init(id, sGroup, config);
15071 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
15074 * The id of the element associated with this object. This is what we
15075 * refer to as the "linked element" because the size and position of
15076 * this element is used to determine when the drag and drop objects have
15084 * Configuration attributes passed into the constructor
15091 * The id of the element that will be dragged. By default this is same
15092 * as the linked element , but could be changed to another element. Ex:
15094 * @property dragElId
15101 * the id of the element that initiates the drag operation. By default
15102 * this is the linked element, but could be changed to be a child of this
15103 * element. This lets us do things like only starting the drag when the
15104 * header element within the linked html element is clicked.
15105 * @property handleElId
15112 * An associative array of HTML tags that will be ignored if clicked.
15113 * @property invalidHandleTypes
15114 * @type {string: string}
15116 invalidHandleTypes: null,
15119 * An associative array of ids for elements that will be ignored if clicked
15120 * @property invalidHandleIds
15121 * @type {string: string}
15123 invalidHandleIds: null,
15126 * An indexted array of css class names for elements that will be ignored
15128 * @property invalidHandleClasses
15131 invalidHandleClasses: null,
15134 * The linked element's absolute X position at the time the drag was
15136 * @property startPageX
15143 * The linked element's absolute X position at the time the drag was
15145 * @property startPageY
15152 * The group defines a logical collection of DragDrop objects that are
15153 * related. Instances only get events when interacting with other
15154 * DragDrop object in the same group. This lets us define multiple
15155 * groups using a single DragDrop subclass if we want.
15157 * @type {string: string}
15162 * Individual drag/drop instances can be locked. This will prevent
15163 * onmousedown start drag.
15171 * Lock this instance
15174 lock: function() { this.locked = true; },
15177 * Unlock this instace
15180 unlock: function() { this.locked = false; },
15183 * By default, all insances can be a drop target. This can be disabled by
15184 * setting isTarget to false.
15191 * The padding configured for this drag and drop object for calculating
15192 * the drop zone intersection with this object.
15199 * Cached reference to the linked element
15200 * @property _domRef
15206 * Internal typeof flag
15207 * @property __ygDragDrop
15210 __ygDragDrop: true,
15213 * Set to true when horizontal contraints are applied
15214 * @property constrainX
15221 * Set to true when vertical contraints are applied
15222 * @property constrainY
15229 * The left constraint
15237 * The right constraint
15245 * The up constraint
15254 * The down constraint
15262 * Maintain offsets when we resetconstraints. Set to true when you want
15263 * the position of the element relative to its parent to stay the same
15264 * when the page changes
15266 * @property maintainOffset
15269 maintainOffset: false,
15272 * Array of pixel locations the element will snap to if we specified a
15273 * horizontal graduation/interval. This array is generated automatically
15274 * when you define a tick interval.
15281 * Array of pixel locations the element will snap to if we specified a
15282 * vertical graduation/interval. This array is generated automatically
15283 * when you define a tick interval.
15290 * By default the drag and drop instance will only respond to the primary
15291 * button click (left button for a right-handed mouse). Set to true to
15292 * allow drag and drop to start with any mouse click that is propogated
15294 * @property primaryButtonOnly
15297 primaryButtonOnly: true,
15300 * The availabe property is false until the linked dom element is accessible.
15301 * @property available
15307 * By default, drags can only be initiated if the mousedown occurs in the
15308 * region the linked element is. This is done in part to work around a
15309 * bug in some browsers that mis-report the mousedown if the previous
15310 * mouseup happened outside of the window. This property is set to true
15311 * if outer handles are defined.
15313 * @property hasOuterHandles
15317 hasOuterHandles: false,
15320 * Code that executes immediately before the startDrag event
15321 * @method b4StartDrag
15324 b4StartDrag: function(x, y) { },
15327 * Abstract method called after a drag/drop object is clicked
15328 * and the drag or mousedown time thresholds have beeen met.
15329 * @method startDrag
15330 * @param {int} X click location
15331 * @param {int} Y click location
15333 startDrag: function(x, y) { /* override this */ },
15336 * Code that executes immediately before the onDrag event
15340 b4Drag: function(e) { },
15343 * Abstract method called during the onMouseMove event while dragging an
15346 * @param {Event} e the mousemove event
15348 onDrag: function(e) { /* override this */ },
15351 * Abstract method called when this element fist begins hovering over
15352 * another DragDrop obj
15353 * @method onDragEnter
15354 * @param {Event} e the mousemove event
15355 * @param {String|DragDrop[]} id In POINT mode, the element
15356 * id this is hovering over. In INTERSECT mode, an array of one or more
15357 * dragdrop items being hovered over.
15359 onDragEnter: function(e, id) { /* override this */ },
15362 * Code that executes immediately before the onDragOver event
15363 * @method b4DragOver
15366 b4DragOver: function(e) { },
15369 * Abstract method called when this element is hovering over another
15371 * @method onDragOver
15372 * @param {Event} e the mousemove event
15373 * @param {String|DragDrop[]} id In POINT mode, the element
15374 * id this is hovering over. In INTERSECT mode, an array of dd items
15375 * being hovered over.
15377 onDragOver: function(e, id) { /* override this */ },
15380 * Code that executes immediately before the onDragOut event
15381 * @method b4DragOut
15384 b4DragOut: function(e) { },
15387 * Abstract method called when we are no longer hovering over an element
15388 * @method onDragOut
15389 * @param {Event} e the mousemove event
15390 * @param {String|DragDrop[]} id In POINT mode, the element
15391 * id this was hovering over. In INTERSECT mode, an array of dd items
15392 * that the mouse is no longer over.
15394 onDragOut: function(e, id) { /* override this */ },
15397 * Code that executes immediately before the onDragDrop event
15398 * @method b4DragDrop
15401 b4DragDrop: function(e) { },
15404 * Abstract method called when this item is dropped on another DragDrop
15406 * @method onDragDrop
15407 * @param {Event} e the mouseup event
15408 * @param {String|DragDrop[]} id In POINT mode, the element
15409 * id this was dropped on. In INTERSECT mode, an array of dd items this
15412 onDragDrop: function(e, id) { /* override this */ },
15415 * Abstract method called when this item is dropped on an area with no
15417 * @method onInvalidDrop
15418 * @param {Event} e the mouseup event
15420 onInvalidDrop: function(e) { /* override this */ },
15423 * Code that executes immediately before the endDrag event
15424 * @method b4EndDrag
15427 b4EndDrag: function(e) { },
15430 * Fired when we are done dragging the object
15432 * @param {Event} e the mouseup event
15434 endDrag: function(e) { /* override this */ },
15437 * Code executed immediately before the onMouseDown event
15438 * @method b4MouseDown
15439 * @param {Event} e the mousedown event
15442 b4MouseDown: function(e) { },
15445 * Event handler that fires when a drag/drop obj gets a mousedown
15446 * @method onMouseDown
15447 * @param {Event} e the mousedown event
15449 onMouseDown: function(e) { /* override this */ },
15452 * Event handler that fires when a drag/drop obj gets a mouseup
15453 * @method onMouseUp
15454 * @param {Event} e the mouseup event
15456 onMouseUp: function(e) { /* override this */ },
15459 * Override the onAvailable method to do what is needed after the initial
15460 * position was determined.
15461 * @method onAvailable
15463 onAvailable: function () {
15467 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
15470 defaultPadding : {left:0, right:0, top:0, bottom:0},
15473 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15477 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15478 { dragElId: "existingProxyDiv" });
15479 dd.startDrag = function(){
15480 this.constrainTo("parent-id");
15483 * Or you can initalize it using the {@link Roo.Element} object:
15485 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15486 startDrag : function(){
15487 this.constrainTo("parent-id");
15491 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15492 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15493 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15494 * an object containing the sides to pad. For example: {right:10, bottom:10}
15495 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15497 constrainTo : function(constrainTo, pad, inContent){
15498 if(typeof pad == "number"){
15499 pad = {left: pad, right:pad, top:pad, bottom:pad};
15501 pad = pad || this.defaultPadding;
15502 var b = Roo.get(this.getEl()).getBox();
15503 var ce = Roo.get(constrainTo);
15504 var s = ce.getScroll();
15505 var c, cd = ce.dom;
15506 if(cd == document.body){
15507 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15510 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15514 var topSpace = b.y - c.y;
15515 var leftSpace = b.x - c.x;
15517 this.resetConstraints();
15518 this.setXConstraint(leftSpace - (pad.left||0), // left
15519 c.width - leftSpace - b.width - (pad.right||0) //right
15521 this.setYConstraint(topSpace - (pad.top||0), //top
15522 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15527 * Returns a reference to the linked element
15529 * @return {HTMLElement} the html element
15531 getEl: function() {
15532 if (!this._domRef) {
15533 this._domRef = Roo.getDom(this.id);
15536 return this._domRef;
15540 * Returns a reference to the actual element to drag. By default this is
15541 * the same as the html element, but it can be assigned to another
15542 * element. An example of this can be found in Roo.dd.DDProxy
15543 * @method getDragEl
15544 * @return {HTMLElement} the html element
15546 getDragEl: function() {
15547 return Roo.getDom(this.dragElId);
15551 * Sets up the DragDrop object. Must be called in the constructor of any
15552 * Roo.dd.DragDrop subclass
15554 * @param id the id of the linked element
15555 * @param {String} sGroup the group of related items
15556 * @param {object} config configuration attributes
15558 init: function(id, sGroup, config) {
15559 this.initTarget(id, sGroup, config);
15560 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15561 // Event.on(this.id, "selectstart", Event.preventDefault);
15565 * Initializes Targeting functionality only... the object does not
15566 * get a mousedown handler.
15567 * @method initTarget
15568 * @param id the id of the linked element
15569 * @param {String} sGroup the group of related items
15570 * @param {object} config configuration attributes
15572 initTarget: function(id, sGroup, config) {
15574 // configuration attributes
15575 this.config = config || {};
15577 // create a local reference to the drag and drop manager
15578 this.DDM = Roo.dd.DDM;
15579 // initialize the groups array
15582 // assume that we have an element reference instead of an id if the
15583 // parameter is not a string
15584 if (typeof id !== "string") {
15591 // add to an interaction group
15592 this.addToGroup((sGroup) ? sGroup : "default");
15594 // We don't want to register this as the handle with the manager
15595 // so we just set the id rather than calling the setter.
15596 this.handleElId = id;
15598 // the linked element is the element that gets dragged by default
15599 this.setDragElId(id);
15601 // by default, clicked anchors will not start drag operations.
15602 this.invalidHandleTypes = { A: "A" };
15603 this.invalidHandleIds = {};
15604 this.invalidHandleClasses = [];
15606 this.applyConfig();
15608 this.handleOnAvailable();
15612 * Applies the configuration parameters that were passed into the constructor.
15613 * This is supposed to happen at each level through the inheritance chain. So
15614 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15615 * DragDrop in order to get all of the parameters that are available in
15617 * @method applyConfig
15619 applyConfig: function() {
15621 // configurable properties:
15622 // padding, isTarget, maintainOffset, primaryButtonOnly
15623 this.padding = this.config.padding || [0, 0, 0, 0];
15624 this.isTarget = (this.config.isTarget !== false);
15625 this.maintainOffset = (this.config.maintainOffset);
15626 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15631 * Executed when the linked element is available
15632 * @method handleOnAvailable
15635 handleOnAvailable: function() {
15636 this.available = true;
15637 this.resetConstraints();
15638 this.onAvailable();
15642 * Configures the padding for the target zone in px. Effectively expands
15643 * (or reduces) the virtual object size for targeting calculations.
15644 * Supports css-style shorthand; if only one parameter is passed, all sides
15645 * will have that padding, and if only two are passed, the top and bottom
15646 * will have the first param, the left and right the second.
15647 * @method setPadding
15648 * @param {int} iTop Top pad
15649 * @param {int} iRight Right pad
15650 * @param {int} iBot Bot pad
15651 * @param {int} iLeft Left pad
15653 setPadding: function(iTop, iRight, iBot, iLeft) {
15654 // this.padding = [iLeft, iRight, iTop, iBot];
15655 if (!iRight && 0 !== iRight) {
15656 this.padding = [iTop, iTop, iTop, iTop];
15657 } else if (!iBot && 0 !== iBot) {
15658 this.padding = [iTop, iRight, iTop, iRight];
15660 this.padding = [iTop, iRight, iBot, iLeft];
15665 * Stores the initial placement of the linked element.
15666 * @method setInitialPosition
15667 * @param {int} diffX the X offset, default 0
15668 * @param {int} diffY the Y offset, default 0
15670 setInitPosition: function(diffX, diffY) {
15671 var el = this.getEl();
15673 if (!this.DDM.verifyEl(el)) {
15677 var dx = diffX || 0;
15678 var dy = diffY || 0;
15680 var p = Dom.getXY( el );
15682 this.initPageX = p[0] - dx;
15683 this.initPageY = p[1] - dy;
15685 this.lastPageX = p[0];
15686 this.lastPageY = p[1];
15689 this.setStartPosition(p);
15693 * Sets the start position of the element. This is set when the obj
15694 * is initialized, the reset when a drag is started.
15695 * @method setStartPosition
15696 * @param pos current position (from previous lookup)
15699 setStartPosition: function(pos) {
15700 var p = pos || Dom.getXY( this.getEl() );
15701 this.deltaSetXY = null;
15703 this.startPageX = p[0];
15704 this.startPageY = p[1];
15708 * Add this instance to a group of related drag/drop objects. All
15709 * instances belong to at least one group, and can belong to as many
15710 * groups as needed.
15711 * @method addToGroup
15712 * @param sGroup {string} the name of the group
15714 addToGroup: function(sGroup) {
15715 this.groups[sGroup] = true;
15716 this.DDM.regDragDrop(this, sGroup);
15720 * Remove's this instance from the supplied interaction group
15721 * @method removeFromGroup
15722 * @param {string} sGroup The group to drop
15724 removeFromGroup: function(sGroup) {
15725 if (this.groups[sGroup]) {
15726 delete this.groups[sGroup];
15729 this.DDM.removeDDFromGroup(this, sGroup);
15733 * Allows you to specify that an element other than the linked element
15734 * will be moved with the cursor during a drag
15735 * @method setDragElId
15736 * @param id {string} the id of the element that will be used to initiate the drag
15738 setDragElId: function(id) {
15739 this.dragElId = id;
15743 * Allows you to specify a child of the linked element that should be
15744 * used to initiate the drag operation. An example of this would be if
15745 * you have a content div with text and links. Clicking anywhere in the
15746 * content area would normally start the drag operation. Use this method
15747 * to specify that an element inside of the content div is the element
15748 * that starts the drag operation.
15749 * @method setHandleElId
15750 * @param id {string} the id of the element that will be used to
15751 * initiate the drag.
15753 setHandleElId: function(id) {
15754 if (typeof id !== "string") {
15757 this.handleElId = id;
15758 this.DDM.regHandle(this.id, id);
15762 * Allows you to set an element outside of the linked element as a drag
15764 * @method setOuterHandleElId
15765 * @param id the id of the element that will be used to initiate the drag
15767 setOuterHandleElId: function(id) {
15768 if (typeof id !== "string") {
15771 Event.on(id, "mousedown",
15772 this.handleMouseDown, this);
15773 this.setHandleElId(id);
15775 this.hasOuterHandles = true;
15779 * Remove all drag and drop hooks for this element
15782 unreg: function() {
15783 Event.un(this.id, "mousedown",
15784 this.handleMouseDown);
15785 this._domRef = null;
15786 this.DDM._remove(this);
15789 destroy : function(){
15794 * Returns true if this instance is locked, or the drag drop mgr is locked
15795 * (meaning that all drag/drop is disabled on the page.)
15797 * @return {boolean} true if this obj or all drag/drop is locked, else
15800 isLocked: function() {
15801 return (this.DDM.isLocked() || this.locked);
15805 * Fired when this object is clicked
15806 * @method handleMouseDown
15808 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15811 handleMouseDown: function(e, oDD){
15812 if (this.primaryButtonOnly && e.button != 0) {
15816 if (this.isLocked()) {
15820 this.DDM.refreshCache(this.groups);
15822 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15823 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15825 if (this.clickValidator(e)) {
15827 // set the initial element position
15828 this.setStartPosition();
15831 this.b4MouseDown(e);
15832 this.onMouseDown(e);
15834 this.DDM.handleMouseDown(e, this);
15836 this.DDM.stopEvent(e);
15844 clickValidator: function(e) {
15845 var target = e.getTarget();
15846 return ( this.isValidHandleChild(target) &&
15847 (this.id == this.handleElId ||
15848 this.DDM.handleWasClicked(target, this.id)) );
15852 * Allows you to specify a tag name that should not start a drag operation
15853 * when clicked. This is designed to facilitate embedding links within a
15854 * drag handle that do something other than start the drag.
15855 * @method addInvalidHandleType
15856 * @param {string} tagName the type of element to exclude
15858 addInvalidHandleType: function(tagName) {
15859 var type = tagName.toUpperCase();
15860 this.invalidHandleTypes[type] = type;
15864 * Lets you to specify an element id for a child of a drag handle
15865 * that should not initiate a drag
15866 * @method addInvalidHandleId
15867 * @param {string} id the element id of the element you wish to ignore
15869 addInvalidHandleId: function(id) {
15870 if (typeof id !== "string") {
15873 this.invalidHandleIds[id] = id;
15877 * Lets you specify a css class of elements that will not initiate a drag
15878 * @method addInvalidHandleClass
15879 * @param {string} cssClass the class of the elements you wish to ignore
15881 addInvalidHandleClass: function(cssClass) {
15882 this.invalidHandleClasses.push(cssClass);
15886 * Unsets an excluded tag name set by addInvalidHandleType
15887 * @method removeInvalidHandleType
15888 * @param {string} tagName the type of element to unexclude
15890 removeInvalidHandleType: function(tagName) {
15891 var type = tagName.toUpperCase();
15892 // this.invalidHandleTypes[type] = null;
15893 delete this.invalidHandleTypes[type];
15897 * Unsets an invalid handle id
15898 * @method removeInvalidHandleId
15899 * @param {string} id the id of the element to re-enable
15901 removeInvalidHandleId: function(id) {
15902 if (typeof id !== "string") {
15905 delete this.invalidHandleIds[id];
15909 * Unsets an invalid css class
15910 * @method removeInvalidHandleClass
15911 * @param {string} cssClass the class of the element(s) you wish to
15914 removeInvalidHandleClass: function(cssClass) {
15915 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15916 if (this.invalidHandleClasses[i] == cssClass) {
15917 delete this.invalidHandleClasses[i];
15923 * Checks the tag exclusion list to see if this click should be ignored
15924 * @method isValidHandleChild
15925 * @param {HTMLElement} node the HTMLElement to evaluate
15926 * @return {boolean} true if this is a valid tag type, false if not
15928 isValidHandleChild: function(node) {
15931 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15934 nodeName = node.nodeName.toUpperCase();
15936 nodeName = node.nodeName;
15938 valid = valid && !this.invalidHandleTypes[nodeName];
15939 valid = valid && !this.invalidHandleIds[node.id];
15941 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15942 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15951 * Create the array of horizontal tick marks if an interval was specified
15952 * in setXConstraint().
15953 * @method setXTicks
15956 setXTicks: function(iStartX, iTickSize) {
15958 this.xTickSize = iTickSize;
15962 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15964 this.xTicks[this.xTicks.length] = i;
15969 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15971 this.xTicks[this.xTicks.length] = i;
15976 this.xTicks.sort(this.DDM.numericSort) ;
15980 * Create the array of vertical tick marks if an interval was specified in
15981 * setYConstraint().
15982 * @method setYTicks
15985 setYTicks: function(iStartY, iTickSize) {
15987 this.yTickSize = iTickSize;
15991 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15993 this.yTicks[this.yTicks.length] = i;
15998 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
16000 this.yTicks[this.yTicks.length] = i;
16005 this.yTicks.sort(this.DDM.numericSort) ;
16009 * By default, the element can be dragged any place on the screen. Use
16010 * this method to limit the horizontal travel of the element. Pass in
16011 * 0,0 for the parameters if you want to lock the drag to the y axis.
16012 * @method setXConstraint
16013 * @param {int} iLeft the number of pixels the element can move to the left
16014 * @param {int} iRight the number of pixels the element can move to the
16016 * @param {int} iTickSize optional parameter for specifying that the
16018 * should move iTickSize pixels at a time.
16020 setXConstraint: function(iLeft, iRight, iTickSize) {
16021 this.leftConstraint = iLeft;
16022 this.rightConstraint = iRight;
16024 this.minX = this.initPageX - iLeft;
16025 this.maxX = this.initPageX + iRight;
16026 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
16028 this.constrainX = true;
16032 * Clears any constraints applied to this instance. Also clears ticks
16033 * since they can't exist independent of a constraint at this time.
16034 * @method clearConstraints
16036 clearConstraints: function() {
16037 this.constrainX = false;
16038 this.constrainY = false;
16043 * Clears any tick interval defined for this instance
16044 * @method clearTicks
16046 clearTicks: function() {
16047 this.xTicks = null;
16048 this.yTicks = null;
16049 this.xTickSize = 0;
16050 this.yTickSize = 0;
16054 * By default, the element can be dragged any place on the screen. Set
16055 * this to limit the vertical travel of the element. Pass in 0,0 for the
16056 * parameters if you want to lock the drag to the x axis.
16057 * @method setYConstraint
16058 * @param {int} iUp the number of pixels the element can move up
16059 * @param {int} iDown the number of pixels the element can move down
16060 * @param {int} iTickSize optional parameter for specifying that the
16061 * element should move iTickSize pixels at a time.
16063 setYConstraint: function(iUp, iDown, iTickSize) {
16064 this.topConstraint = iUp;
16065 this.bottomConstraint = iDown;
16067 this.minY = this.initPageY - iUp;
16068 this.maxY = this.initPageY + iDown;
16069 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
16071 this.constrainY = true;
16076 * resetConstraints must be called if you manually reposition a dd element.
16077 * @method resetConstraints
16078 * @param {boolean} maintainOffset
16080 resetConstraints: function() {
16083 // Maintain offsets if necessary
16084 if (this.initPageX || this.initPageX === 0) {
16085 // figure out how much this thing has moved
16086 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
16087 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
16089 this.setInitPosition(dx, dy);
16091 // This is the first time we have detected the element's position
16093 this.setInitPosition();
16096 if (this.constrainX) {
16097 this.setXConstraint( this.leftConstraint,
16098 this.rightConstraint,
16102 if (this.constrainY) {
16103 this.setYConstraint( this.topConstraint,
16104 this.bottomConstraint,
16110 * Normally the drag element is moved pixel by pixel, but we can specify
16111 * that it move a number of pixels at a time. This method resolves the
16112 * location when we have it set up like this.
16114 * @param {int} val where we want to place the object
16115 * @param {int[]} tickArray sorted array of valid points
16116 * @return {int} the closest tick
16119 getTick: function(val, tickArray) {
16122 // If tick interval is not defined, it is effectively 1 pixel,
16123 // so we return the value passed to us.
16125 } else if (tickArray[0] >= val) {
16126 // The value is lower than the first tick, so we return the first
16128 return tickArray[0];
16130 for (var i=0, len=tickArray.length; i<len; ++i) {
16132 if (tickArray[next] && tickArray[next] >= val) {
16133 var diff1 = val - tickArray[i];
16134 var diff2 = tickArray[next] - val;
16135 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
16139 // The value is larger than the last tick, so we return the last
16141 return tickArray[tickArray.length - 1];
16148 * @return {string} string representation of the dd obj
16150 toString: function() {
16151 return ("DragDrop " + this.id);
16159 * Ext JS Library 1.1.1
16160 * Copyright(c) 2006-2007, Ext JS, LLC.
16162 * Originally Released Under LGPL - original licence link has changed is not relivant.
16165 * <script type="text/javascript">
16170 * The drag and drop utility provides a framework for building drag and drop
16171 * applications. In addition to enabling drag and drop for specific elements,
16172 * the drag and drop elements are tracked by the manager class, and the
16173 * interactions between the various elements are tracked during the drag and
16174 * the implementing code is notified about these important moments.
16177 // Only load the library once. Rewriting the manager class would orphan
16178 // existing drag and drop instances.
16179 if (!Roo.dd.DragDropMgr) {
16182 * @class Roo.dd.DragDropMgr
16183 * DragDropMgr is a singleton that tracks the element interaction for
16184 * all DragDrop items in the window. Generally, you will not call
16185 * this class directly, but it does have helper methods that could
16186 * be useful in your DragDrop implementations.
16189 Roo.dd.DragDropMgr = function() {
16191 var Event = Roo.EventManager;
16196 * Two dimensional Array of registered DragDrop objects. The first
16197 * dimension is the DragDrop item group, the second the DragDrop
16200 * @type {string: string}
16207 * Array of element ids defined as drag handles. Used to determine
16208 * if the element that generated the mousedown event is actually the
16209 * handle and not the html element itself.
16210 * @property handleIds
16211 * @type {string: string}
16218 * the DragDrop object that is currently being dragged
16219 * @property dragCurrent
16227 * the DragDrop object(s) that are being hovered over
16228 * @property dragOvers
16236 * the X distance between the cursor and the object being dragged
16245 * the Y distance between the cursor and the object being dragged
16254 * Flag to determine if we should prevent the default behavior of the
16255 * events we define. By default this is true, but this can be set to
16256 * false if you need the default behavior (not recommended)
16257 * @property preventDefault
16261 preventDefault: true,
16264 * Flag to determine if we should stop the propagation of the events
16265 * we generate. This is true by default but you may want to set it to
16266 * false if the html element contains other features that require the
16268 * @property stopPropagation
16272 stopPropagation: true,
16275 * Internal flag that is set to true when drag and drop has been
16277 * @property initialized
16284 * All drag and drop can be disabled.
16292 * Called the first time an element is registered.
16298 this.initialized = true;
16302 * In point mode, drag and drop interaction is defined by the
16303 * location of the cursor during the drag/drop
16311 * In intersect mode, drag and drop interactio nis defined by the
16312 * overlap of two or more drag and drop objects.
16313 * @property INTERSECT
16320 * The current drag and drop mode. Default: POINT
16328 * Runs method on all drag and drop objects
16329 * @method _execOnAll
16333 _execOnAll: function(sMethod, args) {
16334 for (var i in this.ids) {
16335 for (var j in this.ids[i]) {
16336 var oDD = this.ids[i][j];
16337 if (! this.isTypeOfDD(oDD)) {
16340 oDD[sMethod].apply(oDD, args);
16346 * Drag and drop initialization. Sets up the global event handlers
16351 _onLoad: function() {
16356 Event.on(document, "mouseup", this.handleMouseUp, this, true);
16357 Event.on(document, "mousemove", this.handleMouseMove, this, true);
16358 Event.on(window, "unload", this._onUnload, this, true);
16359 Event.on(window, "resize", this._onResize, this, true);
16360 // Event.on(window, "mouseout", this._test);
16365 * Reset constraints on all drag and drop objs
16366 * @method _onResize
16370 _onResize: function(e) {
16371 this._execOnAll("resetConstraints", []);
16375 * Lock all drag and drop functionality
16379 lock: function() { this.locked = true; },
16382 * Unlock all drag and drop functionality
16386 unlock: function() { this.locked = false; },
16389 * Is drag and drop locked?
16391 * @return {boolean} True if drag and drop is locked, false otherwise.
16394 isLocked: function() { return this.locked; },
16397 * Location cache that is set for all drag drop objects when a drag is
16398 * initiated, cleared when the drag is finished.
16399 * @property locationCache
16406 * Set useCache to false if you want to force object the lookup of each
16407 * drag and drop linked element constantly during a drag.
16408 * @property useCache
16415 * The number of pixels that the mouse needs to move after the
16416 * mousedown before the drag is initiated. Default=3;
16417 * @property clickPixelThresh
16421 clickPixelThresh: 3,
16424 * The number of milliseconds after the mousedown event to initiate the
16425 * drag if we don't get a mouseup event. Default=1000
16426 * @property clickTimeThresh
16430 clickTimeThresh: 350,
16433 * Flag that indicates that either the drag pixel threshold or the
16434 * mousdown time threshold has been met
16435 * @property dragThreshMet
16440 dragThreshMet: false,
16443 * Timeout used for the click time threshold
16444 * @property clickTimeout
16449 clickTimeout: null,
16452 * The X position of the mousedown event stored for later use when a
16453 * drag threshold is met.
16462 * The Y position of the mousedown event stored for later use when a
16463 * drag threshold is met.
16472 * Each DragDrop instance must be registered with the DragDropMgr.
16473 * This is executed in DragDrop.init()
16474 * @method regDragDrop
16475 * @param {DragDrop} oDD the DragDrop object to register
16476 * @param {String} sGroup the name of the group this element belongs to
16479 regDragDrop: function(oDD, sGroup) {
16480 if (!this.initialized) { this.init(); }
16482 if (!this.ids[sGroup]) {
16483 this.ids[sGroup] = {};
16485 this.ids[sGroup][oDD.id] = oDD;
16489 * Removes the supplied dd instance from the supplied group. Executed
16490 * by DragDrop.removeFromGroup, so don't call this function directly.
16491 * @method removeDDFromGroup
16495 removeDDFromGroup: function(oDD, sGroup) {
16496 if (!this.ids[sGroup]) {
16497 this.ids[sGroup] = {};
16500 var obj = this.ids[sGroup];
16501 if (obj && obj[oDD.id]) {
16502 delete obj[oDD.id];
16507 * Unregisters a drag and drop item. This is executed in
16508 * DragDrop.unreg, use that method instead of calling this directly.
16513 _remove: function(oDD) {
16514 for (var g in oDD.groups) {
16515 if (g && this.ids[g][oDD.id]) {
16516 delete this.ids[g][oDD.id];
16519 delete this.handleIds[oDD.id];
16523 * Each DragDrop handle element must be registered. This is done
16524 * automatically when executing DragDrop.setHandleElId()
16525 * @method regHandle
16526 * @param {String} sDDId the DragDrop id this element is a handle for
16527 * @param {String} sHandleId the id of the element that is the drag
16531 regHandle: function(sDDId, sHandleId) {
16532 if (!this.handleIds[sDDId]) {
16533 this.handleIds[sDDId] = {};
16535 this.handleIds[sDDId][sHandleId] = sHandleId;
16539 * Utility function to determine if a given element has been
16540 * registered as a drag drop item.
16541 * @method isDragDrop
16542 * @param {String} id the element id to check
16543 * @return {boolean} true if this element is a DragDrop item,
16547 isDragDrop: function(id) {
16548 return ( this.getDDById(id) ) ? true : false;
16552 * Returns the drag and drop instances that are in all groups the
16553 * passed in instance belongs to.
16554 * @method getRelated
16555 * @param {DragDrop} p_oDD the obj to get related data for
16556 * @param {boolean} bTargetsOnly if true, only return targetable objs
16557 * @return {DragDrop[]} the related instances
16560 getRelated: function(p_oDD, bTargetsOnly) {
16562 for (var i in p_oDD.groups) {
16563 for (j in this.ids[i]) {
16564 var dd = this.ids[i][j];
16565 if (! this.isTypeOfDD(dd)) {
16568 if (!bTargetsOnly || dd.isTarget) {
16569 oDDs[oDDs.length] = dd;
16578 * Returns true if the specified dd target is a legal target for
16579 * the specifice drag obj
16580 * @method isLegalTarget
16581 * @param {DragDrop} the drag obj
16582 * @param {DragDrop} the target
16583 * @return {boolean} true if the target is a legal target for the
16587 isLegalTarget: function (oDD, oTargetDD) {
16588 var targets = this.getRelated(oDD, true);
16589 for (var i=0, len=targets.length;i<len;++i) {
16590 if (targets[i].id == oTargetDD.id) {
16599 * My goal is to be able to transparently determine if an object is
16600 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16601 * returns "object", oDD.constructor.toString() always returns
16602 * "DragDrop" and not the name of the subclass. So for now it just
16603 * evaluates a well-known variable in DragDrop.
16604 * @method isTypeOfDD
16605 * @param {Object} the object to evaluate
16606 * @return {boolean} true if typeof oDD = DragDrop
16609 isTypeOfDD: function (oDD) {
16610 return (oDD && oDD.__ygDragDrop);
16614 * Utility function to determine if a given element has been
16615 * registered as a drag drop handle for the given Drag Drop object.
16617 * @param {String} id the element id to check
16618 * @return {boolean} true if this element is a DragDrop handle, false
16622 isHandle: function(sDDId, sHandleId) {
16623 return ( this.handleIds[sDDId] &&
16624 this.handleIds[sDDId][sHandleId] );
16628 * Returns the DragDrop instance for a given id
16629 * @method getDDById
16630 * @param {String} id the id of the DragDrop object
16631 * @return {DragDrop} the drag drop object, null if it is not found
16634 getDDById: function(id) {
16635 for (var i in this.ids) {
16636 if (this.ids[i][id]) {
16637 return this.ids[i][id];
16644 * Fired after a registered DragDrop object gets the mousedown event.
16645 * Sets up the events required to track the object being dragged
16646 * @method handleMouseDown
16647 * @param {Event} e the event
16648 * @param oDD the DragDrop object being dragged
16652 handleMouseDown: function(e, oDD) {
16654 Roo.QuickTips.disable();
16656 this.currentTarget = e.getTarget();
16658 this.dragCurrent = oDD;
16660 var el = oDD.getEl();
16662 // track start position
16663 this.startX = e.getPageX();
16664 this.startY = e.getPageY();
16666 this.deltaX = this.startX - el.offsetLeft;
16667 this.deltaY = this.startY - el.offsetTop;
16669 this.dragThreshMet = false;
16671 this.clickTimeout = setTimeout(
16673 var DDM = Roo.dd.DDM;
16674 DDM.startDrag(DDM.startX, DDM.startY);
16676 this.clickTimeThresh );
16680 * Fired when either the drag pixel threshol or the mousedown hold
16681 * time threshold has been met.
16682 * @method startDrag
16683 * @param x {int} the X position of the original mousedown
16684 * @param y {int} the Y position of the original mousedown
16687 startDrag: function(x, y) {
16688 clearTimeout(this.clickTimeout);
16689 if (this.dragCurrent) {
16690 this.dragCurrent.b4StartDrag(x, y);
16691 this.dragCurrent.startDrag(x, y);
16693 this.dragThreshMet = true;
16697 * Internal function to handle the mouseup event. Will be invoked
16698 * from the context of the document.
16699 * @method handleMouseUp
16700 * @param {Event} e the event
16704 handleMouseUp: function(e) {
16707 Roo.QuickTips.enable();
16709 if (! this.dragCurrent) {
16713 clearTimeout(this.clickTimeout);
16715 if (this.dragThreshMet) {
16716 this.fireEvents(e, true);
16726 * Utility to stop event propagation and event default, if these
16727 * features are turned on.
16728 * @method stopEvent
16729 * @param {Event} e the event as returned by this.getEvent()
16732 stopEvent: function(e){
16733 if(this.stopPropagation) {
16734 e.stopPropagation();
16737 if (this.preventDefault) {
16738 e.preventDefault();
16743 * Internal function to clean up event handlers after the drag
16744 * operation is complete
16746 * @param {Event} e the event
16750 stopDrag: function(e) {
16751 // Fire the drag end event for the item that was dragged
16752 if (this.dragCurrent) {
16753 if (this.dragThreshMet) {
16754 this.dragCurrent.b4EndDrag(e);
16755 this.dragCurrent.endDrag(e);
16758 this.dragCurrent.onMouseUp(e);
16761 this.dragCurrent = null;
16762 this.dragOvers = {};
16766 * Internal function to handle the mousemove event. Will be invoked
16767 * from the context of the html element.
16769 * @TODO figure out what we can do about mouse events lost when the
16770 * user drags objects beyond the window boundary. Currently we can
16771 * detect this in internet explorer by verifying that the mouse is
16772 * down during the mousemove event. Firefox doesn't give us the
16773 * button state on the mousemove event.
16774 * @method handleMouseMove
16775 * @param {Event} e the event
16779 handleMouseMove: function(e) {
16780 if (! this.dragCurrent) {
16784 // var button = e.which || e.button;
16786 // check for IE mouseup outside of page boundary
16787 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16789 return this.handleMouseUp(e);
16792 if (!this.dragThreshMet) {
16793 var diffX = Math.abs(this.startX - e.getPageX());
16794 var diffY = Math.abs(this.startY - e.getPageY());
16795 if (diffX > this.clickPixelThresh ||
16796 diffY > this.clickPixelThresh) {
16797 this.startDrag(this.startX, this.startY);
16801 if (this.dragThreshMet) {
16802 this.dragCurrent.b4Drag(e);
16803 this.dragCurrent.onDrag(e);
16804 if(!this.dragCurrent.moveOnly){
16805 this.fireEvents(e, false);
16815 * Iterates over all of the DragDrop elements to find ones we are
16816 * hovering over or dropping on
16817 * @method fireEvents
16818 * @param {Event} e the event
16819 * @param {boolean} isDrop is this a drop op or a mouseover op?
16823 fireEvents: function(e, isDrop) {
16824 var dc = this.dragCurrent;
16826 // If the user did the mouse up outside of the window, we could
16827 // get here even though we have ended the drag.
16828 if (!dc || dc.isLocked()) {
16832 var pt = e.getPoint();
16834 // cache the previous dragOver array
16840 var enterEvts = [];
16842 // Check to see if the object(s) we were hovering over is no longer
16843 // being hovered over so we can fire the onDragOut event
16844 for (var i in this.dragOvers) {
16846 var ddo = this.dragOvers[i];
16848 if (! this.isTypeOfDD(ddo)) {
16852 if (! this.isOverTarget(pt, ddo, this.mode)) {
16853 outEvts.push( ddo );
16856 oldOvers[i] = true;
16857 delete this.dragOvers[i];
16860 for (var sGroup in dc.groups) {
16862 if ("string" != typeof sGroup) {
16866 for (i in this.ids[sGroup]) {
16867 var oDD = this.ids[sGroup][i];
16868 if (! this.isTypeOfDD(oDD)) {
16872 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16873 if (this.isOverTarget(pt, oDD, this.mode)) {
16874 // look for drop interactions
16876 dropEvts.push( oDD );
16877 // look for drag enter and drag over interactions
16880 // initial drag over: dragEnter fires
16881 if (!oldOvers[oDD.id]) {
16882 enterEvts.push( oDD );
16883 // subsequent drag overs: dragOver fires
16885 overEvts.push( oDD );
16888 this.dragOvers[oDD.id] = oDD;
16896 if (outEvts.length) {
16897 dc.b4DragOut(e, outEvts);
16898 dc.onDragOut(e, outEvts);
16901 if (enterEvts.length) {
16902 dc.onDragEnter(e, enterEvts);
16905 if (overEvts.length) {
16906 dc.b4DragOver(e, overEvts);
16907 dc.onDragOver(e, overEvts);
16910 if (dropEvts.length) {
16911 dc.b4DragDrop(e, dropEvts);
16912 dc.onDragDrop(e, dropEvts);
16916 // fire dragout events
16918 for (i=0, len=outEvts.length; i<len; ++i) {
16919 dc.b4DragOut(e, outEvts[i].id);
16920 dc.onDragOut(e, outEvts[i].id);
16923 // fire enter events
16924 for (i=0,len=enterEvts.length; i<len; ++i) {
16925 // dc.b4DragEnter(e, oDD.id);
16926 dc.onDragEnter(e, enterEvts[i].id);
16929 // fire over events
16930 for (i=0,len=overEvts.length; i<len; ++i) {
16931 dc.b4DragOver(e, overEvts[i].id);
16932 dc.onDragOver(e, overEvts[i].id);
16935 // fire drop events
16936 for (i=0, len=dropEvts.length; i<len; ++i) {
16937 dc.b4DragDrop(e, dropEvts[i].id);
16938 dc.onDragDrop(e, dropEvts[i].id);
16943 // notify about a drop that did not find a target
16944 if (isDrop && !dropEvts.length) {
16945 dc.onInvalidDrop(e);
16951 * Helper function for getting the best match from the list of drag
16952 * and drop objects returned by the drag and drop events when we are
16953 * in INTERSECT mode. It returns either the first object that the
16954 * cursor is over, or the object that has the greatest overlap with
16955 * the dragged element.
16956 * @method getBestMatch
16957 * @param {DragDrop[]} dds The array of drag and drop objects
16959 * @return {DragDrop} The best single match
16962 getBestMatch: function(dds) {
16964 // Return null if the input is not what we expect
16965 //if (!dds || !dds.length || dds.length == 0) {
16967 // If there is only one item, it wins
16968 //} else if (dds.length == 1) {
16970 var len = dds.length;
16975 // Loop through the targeted items
16976 for (var i=0; i<len; ++i) {
16978 // If the cursor is over the object, it wins. If the
16979 // cursor is over multiple matches, the first one we come
16981 if (dd.cursorIsOver) {
16984 // Otherwise the object with the most overlap wins
16987 winner.overlap.getArea() < dd.overlap.getArea()) {
16998 * Refreshes the cache of the top-left and bottom-right points of the
16999 * drag and drop objects in the specified group(s). This is in the
17000 * format that is stored in the drag and drop instance, so typical
17003 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
17007 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
17009 * @TODO this really should be an indexed array. Alternatively this
17010 * method could accept both.
17011 * @method refreshCache
17012 * @param {Object} groups an associative array of groups to refresh
17015 refreshCache: function(groups) {
17016 for (var sGroup in groups) {
17017 if ("string" != typeof sGroup) {
17020 for (var i in this.ids[sGroup]) {
17021 var oDD = this.ids[sGroup][i];
17023 if (this.isTypeOfDD(oDD)) {
17024 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
17025 var loc = this.getLocation(oDD);
17027 this.locationCache[oDD.id] = loc;
17029 delete this.locationCache[oDD.id];
17030 // this will unregister the drag and drop object if
17031 // the element is not in a usable state
17040 * This checks to make sure an element exists and is in the DOM. The
17041 * main purpose is to handle cases where innerHTML is used to remove
17042 * drag and drop objects from the DOM. IE provides an 'unspecified
17043 * error' when trying to access the offsetParent of such an element
17045 * @param {HTMLElement} el the element to check
17046 * @return {boolean} true if the element looks usable
17049 verifyEl: function(el) {
17054 parent = el.offsetParent;
17057 parent = el.offsetParent;
17068 * Returns a Region object containing the drag and drop element's position
17069 * and size, including the padding configured for it
17070 * @method getLocation
17071 * @param {DragDrop} oDD the drag and drop object to get the
17073 * @return {Roo.lib.Region} a Region object representing the total area
17074 * the element occupies, including any padding
17075 * the instance is configured for.
17078 getLocation: function(oDD) {
17079 if (! this.isTypeOfDD(oDD)) {
17083 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
17086 pos= Roo.lib.Dom.getXY(el);
17094 x2 = x1 + el.offsetWidth;
17096 y2 = y1 + el.offsetHeight;
17098 t = y1 - oDD.padding[0];
17099 r = x2 + oDD.padding[1];
17100 b = y2 + oDD.padding[2];
17101 l = x1 - oDD.padding[3];
17103 return new Roo.lib.Region( t, r, b, l );
17107 * Checks the cursor location to see if it over the target
17108 * @method isOverTarget
17109 * @param {Roo.lib.Point} pt The point to evaluate
17110 * @param {DragDrop} oTarget the DragDrop object we are inspecting
17111 * @return {boolean} true if the mouse is over the target
17115 isOverTarget: function(pt, oTarget, intersect) {
17116 // use cache if available
17117 var loc = this.locationCache[oTarget.id];
17118 if (!loc || !this.useCache) {
17119 loc = this.getLocation(oTarget);
17120 this.locationCache[oTarget.id] = loc;
17128 oTarget.cursorIsOver = loc.contains( pt );
17130 // DragDrop is using this as a sanity check for the initial mousedown
17131 // in this case we are done. In POINT mode, if the drag obj has no
17132 // contraints, we are also done. Otherwise we need to evaluate the
17133 // location of the target as related to the actual location of the
17134 // dragged element.
17135 var dc = this.dragCurrent;
17136 if (!dc || !dc.getTargetCoord ||
17137 (!intersect && !dc.constrainX && !dc.constrainY)) {
17138 return oTarget.cursorIsOver;
17141 oTarget.overlap = null;
17143 // Get the current location of the drag element, this is the
17144 // location of the mouse event less the delta that represents
17145 // where the original mousedown happened on the element. We
17146 // need to consider constraints and ticks as well.
17147 var pos = dc.getTargetCoord(pt.x, pt.y);
17149 var el = dc.getDragEl();
17150 var curRegion = new Roo.lib.Region( pos.y,
17151 pos.x + el.offsetWidth,
17152 pos.y + el.offsetHeight,
17155 var overlap = curRegion.intersect(loc);
17158 oTarget.overlap = overlap;
17159 return (intersect) ? true : oTarget.cursorIsOver;
17166 * unload event handler
17167 * @method _onUnload
17171 _onUnload: function(e, me) {
17172 Roo.dd.DragDropMgr.unregAll();
17176 * Cleans up the drag and drop events and objects.
17181 unregAll: function() {
17183 if (this.dragCurrent) {
17185 this.dragCurrent = null;
17188 this._execOnAll("unreg", []);
17190 for (i in this.elementCache) {
17191 delete this.elementCache[i];
17194 this.elementCache = {};
17199 * A cache of DOM elements
17200 * @property elementCache
17207 * Get the wrapper for the DOM element specified
17208 * @method getElWrapper
17209 * @param {String} id the id of the element to get
17210 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
17212 * @deprecated This wrapper isn't that useful
17215 getElWrapper: function(id) {
17216 var oWrapper = this.elementCache[id];
17217 if (!oWrapper || !oWrapper.el) {
17218 oWrapper = this.elementCache[id] =
17219 new this.ElementWrapper(Roo.getDom(id));
17225 * Returns the actual DOM element
17226 * @method getElement
17227 * @param {String} id the id of the elment to get
17228 * @return {Object} The element
17229 * @deprecated use Roo.getDom instead
17232 getElement: function(id) {
17233 return Roo.getDom(id);
17237 * Returns the style property for the DOM element (i.e.,
17238 * document.getElById(id).style)
17240 * @param {String} id the id of the elment to get
17241 * @return {Object} The style property of the element
17242 * @deprecated use Roo.getDom instead
17245 getCss: function(id) {
17246 var el = Roo.getDom(id);
17247 return (el) ? el.style : null;
17251 * Inner class for cached elements
17252 * @class DragDropMgr.ElementWrapper
17257 ElementWrapper: function(el) {
17262 this.el = el || null;
17267 this.id = this.el && el.id;
17269 * A reference to the style property
17272 this.css = this.el && el.style;
17276 * Returns the X position of an html element
17278 * @param el the element for which to get the position
17279 * @return {int} the X coordinate
17281 * @deprecated use Roo.lib.Dom.getX instead
17284 getPosX: function(el) {
17285 return Roo.lib.Dom.getX(el);
17289 * Returns the Y position of an html element
17291 * @param el the element for which to get the position
17292 * @return {int} the Y coordinate
17293 * @deprecated use Roo.lib.Dom.getY instead
17296 getPosY: function(el) {
17297 return Roo.lib.Dom.getY(el);
17301 * Swap two nodes. In IE, we use the native method, for others we
17302 * emulate the IE behavior
17304 * @param n1 the first node to swap
17305 * @param n2 the other node to swap
17308 swapNode: function(n1, n2) {
17312 var p = n2.parentNode;
17313 var s = n2.nextSibling;
17316 p.insertBefore(n1, n2);
17317 } else if (n2 == n1.nextSibling) {
17318 p.insertBefore(n2, n1);
17320 n1.parentNode.replaceChild(n2, n1);
17321 p.insertBefore(n1, s);
17327 * Returns the current scroll position
17328 * @method getScroll
17332 getScroll: function () {
17333 var t, l, dde=document.documentElement, db=document.body;
17334 if (dde && (dde.scrollTop || dde.scrollLeft)) {
17336 l = dde.scrollLeft;
17343 return { top: t, left: l };
17347 * Returns the specified element style property
17349 * @param {HTMLElement} el the element
17350 * @param {string} styleProp the style property
17351 * @return {string} The value of the style property
17352 * @deprecated use Roo.lib.Dom.getStyle
17355 getStyle: function(el, styleProp) {
17356 return Roo.fly(el).getStyle(styleProp);
17360 * Gets the scrollTop
17361 * @method getScrollTop
17362 * @return {int} the document's scrollTop
17365 getScrollTop: function () { return this.getScroll().top; },
17368 * Gets the scrollLeft
17369 * @method getScrollLeft
17370 * @return {int} the document's scrollTop
17373 getScrollLeft: function () { return this.getScroll().left; },
17376 * Sets the x/y position of an element to the location of the
17379 * @param {HTMLElement} moveEl The element to move
17380 * @param {HTMLElement} targetEl The position reference element
17383 moveToEl: function (moveEl, targetEl) {
17384 var aCoord = Roo.lib.Dom.getXY(targetEl);
17385 Roo.lib.Dom.setXY(moveEl, aCoord);
17389 * Numeric array sort function
17390 * @method numericSort
17393 numericSort: function(a, b) { return (a - b); },
17397 * @property _timeoutCount
17404 * Trying to make the load order less important. Without this we get
17405 * an error if this file is loaded before the Event Utility.
17406 * @method _addListeners
17410 _addListeners: function() {
17411 var DDM = Roo.dd.DDM;
17412 if ( Roo.lib.Event && document ) {
17415 if (DDM._timeoutCount > 2000) {
17417 setTimeout(DDM._addListeners, 10);
17418 if (document && document.body) {
17419 DDM._timeoutCount += 1;
17426 * Recursively searches the immediate parent and all child nodes for
17427 * the handle element in order to determine wheter or not it was
17429 * @method handleWasClicked
17430 * @param node the html element to inspect
17433 handleWasClicked: function(node, id) {
17434 if (this.isHandle(id, node.id)) {
17437 // check to see if this is a text node child of the one we want
17438 var p = node.parentNode;
17441 if (this.isHandle(id, p.id)) {
17456 // shorter alias, save a few bytes
17457 Roo.dd.DDM = Roo.dd.DragDropMgr;
17458 Roo.dd.DDM._addListeners();
17462 * Ext JS Library 1.1.1
17463 * Copyright(c) 2006-2007, Ext JS, LLC.
17465 * Originally Released Under LGPL - original licence link has changed is not relivant.
17468 * <script type="text/javascript">
17473 * A DragDrop implementation where the linked element follows the
17474 * mouse cursor during a drag.
17475 * @extends Roo.dd.DragDrop
17477 * @param {String} id the id of the linked element
17478 * @param {String} sGroup the group of related DragDrop items
17479 * @param {object} config an object containing configurable attributes
17480 * Valid properties for DD:
17483 Roo.dd.DD = function(id, sGroup, config) {
17485 this.init(id, sGroup, config);
17489 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17492 * When set to true, the utility automatically tries to scroll the browser
17493 * window wehn a drag and drop element is dragged near the viewport boundary.
17494 * Defaults to true.
17501 * Sets the pointer offset to the distance between the linked element's top
17502 * left corner and the location the element was clicked
17503 * @method autoOffset
17504 * @param {int} iPageX the X coordinate of the click
17505 * @param {int} iPageY the Y coordinate of the click
17507 autoOffset: function(iPageX, iPageY) {
17508 var x = iPageX - this.startPageX;
17509 var y = iPageY - this.startPageY;
17510 this.setDelta(x, y);
17514 * Sets the pointer offset. You can call this directly to force the
17515 * offset to be in a particular location (e.g., pass in 0,0 to set it
17516 * to the center of the object)
17518 * @param {int} iDeltaX the distance from the left
17519 * @param {int} iDeltaY the distance from the top
17521 setDelta: function(iDeltaX, iDeltaY) {
17522 this.deltaX = iDeltaX;
17523 this.deltaY = iDeltaY;
17527 * Sets the drag element to the location of the mousedown or click event,
17528 * maintaining the cursor location relative to the location on the element
17529 * that was clicked. Override this if you want to place the element in a
17530 * location other than where the cursor is.
17531 * @method setDragElPos
17532 * @param {int} iPageX the X coordinate of the mousedown or drag event
17533 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17535 setDragElPos: function(iPageX, iPageY) {
17536 // the first time we do this, we are going to check to make sure
17537 // the element has css positioning
17539 var el = this.getDragEl();
17540 this.alignElWithMouse(el, iPageX, iPageY);
17544 * Sets the element to the location of the mousedown or click event,
17545 * maintaining the cursor location relative to the location on the element
17546 * that was clicked. Override this if you want to place the element in a
17547 * location other than where the cursor is.
17548 * @method alignElWithMouse
17549 * @param {HTMLElement} el the element to move
17550 * @param {int} iPageX the X coordinate of the mousedown or drag event
17551 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17553 alignElWithMouse: function(el, iPageX, iPageY) {
17554 var oCoord = this.getTargetCoord(iPageX, iPageY);
17555 var fly = el.dom ? el : Roo.fly(el);
17556 if (!this.deltaSetXY) {
17557 var aCoord = [oCoord.x, oCoord.y];
17559 var newLeft = fly.getLeft(true);
17560 var newTop = fly.getTop(true);
17561 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17563 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17566 this.cachePosition(oCoord.x, oCoord.y);
17567 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17572 * Saves the most recent position so that we can reset the constraints and
17573 * tick marks on-demand. We need to know this so that we can calculate the
17574 * number of pixels the element is offset from its original position.
17575 * @method cachePosition
17576 * @param iPageX the current x position (optional, this just makes it so we
17577 * don't have to look it up again)
17578 * @param iPageY the current y position (optional, this just makes it so we
17579 * don't have to look it up again)
17581 cachePosition: function(iPageX, iPageY) {
17583 this.lastPageX = iPageX;
17584 this.lastPageY = iPageY;
17586 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17587 this.lastPageX = aCoord[0];
17588 this.lastPageY = aCoord[1];
17593 * Auto-scroll the window if the dragged object has been moved beyond the
17594 * visible window boundary.
17595 * @method autoScroll
17596 * @param {int} x the drag element's x position
17597 * @param {int} y the drag element's y position
17598 * @param {int} h the height of the drag element
17599 * @param {int} w the width of the drag element
17602 autoScroll: function(x, y, h, w) {
17605 // The client height
17606 var clientH = Roo.lib.Dom.getViewWidth();
17608 // The client width
17609 var clientW = Roo.lib.Dom.getViewHeight();
17611 // The amt scrolled down
17612 var st = this.DDM.getScrollTop();
17614 // The amt scrolled right
17615 var sl = this.DDM.getScrollLeft();
17617 // Location of the bottom of the element
17620 // Location of the right of the element
17623 // The distance from the cursor to the bottom of the visible area,
17624 // adjusted so that we don't scroll if the cursor is beyond the
17625 // element drag constraints
17626 var toBot = (clientH + st - y - this.deltaY);
17628 // The distance from the cursor to the right of the visible area
17629 var toRight = (clientW + sl - x - this.deltaX);
17632 // How close to the edge the cursor must be before we scroll
17633 // var thresh = (document.all) ? 100 : 40;
17636 // How many pixels to scroll per autoscroll op. This helps to reduce
17637 // clunky scrolling. IE is more sensitive about this ... it needs this
17638 // value to be higher.
17639 var scrAmt = (document.all) ? 80 : 30;
17641 // Scroll down if we are near the bottom of the visible page and the
17642 // obj extends below the crease
17643 if ( bot > clientH && toBot < thresh ) {
17644 window.scrollTo(sl, st + scrAmt);
17647 // Scroll up if the window is scrolled down and the top of the object
17648 // goes above the top border
17649 if ( y < st && st > 0 && y - st < thresh ) {
17650 window.scrollTo(sl, st - scrAmt);
17653 // Scroll right if the obj is beyond the right border and the cursor is
17654 // near the border.
17655 if ( right > clientW && toRight < thresh ) {
17656 window.scrollTo(sl + scrAmt, st);
17659 // Scroll left if the window has been scrolled to the right and the obj
17660 // extends past the left border
17661 if ( x < sl && sl > 0 && x - sl < thresh ) {
17662 window.scrollTo(sl - scrAmt, st);
17668 * Finds the location the element should be placed if we want to move
17669 * it to where the mouse location less the click offset would place us.
17670 * @method getTargetCoord
17671 * @param {int} iPageX the X coordinate of the click
17672 * @param {int} iPageY the Y coordinate of the click
17673 * @return an object that contains the coordinates (Object.x and Object.y)
17676 getTargetCoord: function(iPageX, iPageY) {
17679 var x = iPageX - this.deltaX;
17680 var y = iPageY - this.deltaY;
17682 if (this.constrainX) {
17683 if (x < this.minX) { x = this.minX; }
17684 if (x > this.maxX) { x = this.maxX; }
17687 if (this.constrainY) {
17688 if (y < this.minY) { y = this.minY; }
17689 if (y > this.maxY) { y = this.maxY; }
17692 x = this.getTick(x, this.xTicks);
17693 y = this.getTick(y, this.yTicks);
17700 * Sets up config options specific to this class. Overrides
17701 * Roo.dd.DragDrop, but all versions of this method through the
17702 * inheritance chain are called
17704 applyConfig: function() {
17705 Roo.dd.DD.superclass.applyConfig.call(this);
17706 this.scroll = (this.config.scroll !== false);
17710 * Event that fires prior to the onMouseDown event. Overrides
17713 b4MouseDown: function(e) {
17714 // this.resetConstraints();
17715 this.autoOffset(e.getPageX(),
17720 * Event that fires prior to the onDrag event. Overrides
17723 b4Drag: function(e) {
17724 this.setDragElPos(e.getPageX(),
17728 toString: function() {
17729 return ("DD " + this.id);
17732 //////////////////////////////////////////////////////////////////////////
17733 // Debugging ygDragDrop events that can be overridden
17734 //////////////////////////////////////////////////////////////////////////
17736 startDrag: function(x, y) {
17739 onDrag: function(e) {
17742 onDragEnter: function(e, id) {
17745 onDragOver: function(e, id) {
17748 onDragOut: function(e, id) {
17751 onDragDrop: function(e, id) {
17754 endDrag: function(e) {
17761 * Ext JS Library 1.1.1
17762 * Copyright(c) 2006-2007, Ext JS, LLC.
17764 * Originally Released Under LGPL - original licence link has changed is not relivant.
17767 * <script type="text/javascript">
17771 * @class Roo.dd.DDProxy
17772 * A DragDrop implementation that inserts an empty, bordered div into
17773 * the document that follows the cursor during drag operations. At the time of
17774 * the click, the frame div is resized to the dimensions of the linked html
17775 * element, and moved to the exact location of the linked element.
17777 * References to the "frame" element refer to the single proxy element that
17778 * was created to be dragged in place of all DDProxy elements on the
17781 * @extends Roo.dd.DD
17783 * @param {String} id the id of the linked html element
17784 * @param {String} sGroup the group of related DragDrop objects
17785 * @param {object} config an object containing configurable attributes
17786 * Valid properties for DDProxy in addition to those in DragDrop:
17787 * resizeFrame, centerFrame, dragElId
17789 Roo.dd.DDProxy = function(id, sGroup, config) {
17791 this.init(id, sGroup, config);
17797 * The default drag frame div id
17798 * @property Roo.dd.DDProxy.dragElId
17802 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17804 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17807 * By default we resize the drag frame to be the same size as the element
17808 * we want to drag (this is to get the frame effect). We can turn it off
17809 * if we want a different behavior.
17810 * @property resizeFrame
17816 * By default the frame is positioned exactly where the drag element is, so
17817 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17818 * you do not have constraints on the obj is to have the drag frame centered
17819 * around the cursor. Set centerFrame to true for this effect.
17820 * @property centerFrame
17823 centerFrame: false,
17826 * Creates the proxy element if it does not yet exist
17827 * @method createFrame
17829 createFrame: function() {
17831 var body = document.body;
17833 if (!body || !body.firstChild) {
17834 setTimeout( function() { self.createFrame(); }, 50 );
17838 var div = this.getDragEl();
17841 div = document.createElement("div");
17842 div.id = this.dragElId;
17845 s.position = "absolute";
17846 s.visibility = "hidden";
17848 s.border = "2px solid #aaa";
17851 // appendChild can blow up IE if invoked prior to the window load event
17852 // while rendering a table. It is possible there are other scenarios
17853 // that would cause this to happen as well.
17854 body.insertBefore(div, body.firstChild);
17859 * Initialization for the drag frame element. Must be called in the
17860 * constructor of all subclasses
17861 * @method initFrame
17863 initFrame: function() {
17864 this.createFrame();
17867 applyConfig: function() {
17868 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17870 this.resizeFrame = (this.config.resizeFrame !== false);
17871 this.centerFrame = (this.config.centerFrame);
17872 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17876 * Resizes the drag frame to the dimensions of the clicked object, positions
17877 * it over the object, and finally displays it
17878 * @method showFrame
17879 * @param {int} iPageX X click position
17880 * @param {int} iPageY Y click position
17883 showFrame: function(iPageX, iPageY) {
17884 var el = this.getEl();
17885 var dragEl = this.getDragEl();
17886 var s = dragEl.style;
17888 this._resizeProxy();
17890 if (this.centerFrame) {
17891 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17892 Math.round(parseInt(s.height, 10)/2) );
17895 this.setDragElPos(iPageX, iPageY);
17897 Roo.fly(dragEl).show();
17901 * The proxy is automatically resized to the dimensions of the linked
17902 * element when a drag is initiated, unless resizeFrame is set to false
17903 * @method _resizeProxy
17906 _resizeProxy: function() {
17907 if (this.resizeFrame) {
17908 var el = this.getEl();
17909 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17913 // overrides Roo.dd.DragDrop
17914 b4MouseDown: function(e) {
17915 var x = e.getPageX();
17916 var y = e.getPageY();
17917 this.autoOffset(x, y);
17918 this.setDragElPos(x, y);
17921 // overrides Roo.dd.DragDrop
17922 b4StartDrag: function(x, y) {
17923 // show the drag frame
17924 this.showFrame(x, y);
17927 // overrides Roo.dd.DragDrop
17928 b4EndDrag: function(e) {
17929 Roo.fly(this.getDragEl()).hide();
17932 // overrides Roo.dd.DragDrop
17933 // By default we try to move the element to the last location of the frame.
17934 // This is so that the default behavior mirrors that of Roo.dd.DD.
17935 endDrag: function(e) {
17937 var lel = this.getEl();
17938 var del = this.getDragEl();
17940 // Show the drag frame briefly so we can get its position
17941 del.style.visibility = "";
17944 // Hide the linked element before the move to get around a Safari
17946 lel.style.visibility = "hidden";
17947 Roo.dd.DDM.moveToEl(lel, del);
17948 del.style.visibility = "hidden";
17949 lel.style.visibility = "";
17954 beforeMove : function(){
17958 afterDrag : function(){
17962 toString: function() {
17963 return ("DDProxy " + this.id);
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.DDTarget
17980 * A DragDrop implementation that does not move, but can be a drop
17981 * target. You would get the same result by simply omitting implementation
17982 * for the event callbacks, but this way we reduce the processing cost of the
17983 * event listener and the callbacks.
17984 * @extends Roo.dd.DragDrop
17986 * @param {String} id the id of the element that is a drop target
17987 * @param {String} sGroup the group of related DragDrop objects
17988 * @param {object} config an object containing configurable attributes
17989 * Valid properties for DDTarget in addition to those in
17993 Roo.dd.DDTarget = function(id, sGroup, config) {
17995 this.initTarget(id, sGroup, config);
17997 if (config.listeners || config.events) {
17998 Roo.dd.DragDrop.superclass.constructor.call(this, {
17999 listeners : config.listeners || {},
18000 events : config.events || {}
18005 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
18006 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
18007 toString: function() {
18008 return ("DDTarget " + this.id);
18013 * Ext JS Library 1.1.1
18014 * Copyright(c) 2006-2007, Ext JS, LLC.
18016 * Originally Released Under LGPL - original licence link has changed is not relivant.
18019 * <script type="text/javascript">
18024 * @class Roo.dd.ScrollManager
18025 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
18026 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
18029 Roo.dd.ScrollManager = function(){
18030 var ddm = Roo.dd.DragDropMgr;
18037 var onStop = function(e){
18042 var triggerRefresh = function(){
18043 if(ddm.dragCurrent){
18044 ddm.refreshCache(ddm.dragCurrent.groups);
18048 var doScroll = function(){
18049 if(ddm.dragCurrent){
18050 var dds = Roo.dd.ScrollManager;
18052 if(proc.el.scroll(proc.dir, dds.increment)){
18056 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
18061 var clearProc = function(){
18063 clearInterval(proc.id);
18070 var startProc = function(el, dir){
18071 Roo.log('scroll startproc');
18075 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
18078 var onFire = function(e, isDrop){
18080 if(isDrop || !ddm.dragCurrent){ return; }
18081 var dds = Roo.dd.ScrollManager;
18082 if(!dragEl || dragEl != ddm.dragCurrent){
18083 dragEl = ddm.dragCurrent;
18084 // refresh regions on drag start
18085 dds.refreshCache();
18088 var xy = Roo.lib.Event.getXY(e);
18089 var pt = new Roo.lib.Point(xy[0], xy[1]);
18090 for(var id in els){
18091 var el = els[id], r = el._region;
18092 if(r && r.contains(pt) && el.isScrollable()){
18093 if(r.bottom - pt.y <= dds.thresh){
18095 startProc(el, "down");
18098 }else if(r.right - pt.x <= dds.thresh){
18100 startProc(el, "left");
18103 }else if(pt.y - r.top <= dds.thresh){
18105 startProc(el, "up");
18108 }else if(pt.x - r.left <= dds.thresh){
18110 startProc(el, "right");
18119 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
18120 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
18124 * Registers new overflow element(s) to auto scroll
18125 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
18127 register : function(el){
18128 if(el instanceof Array){
18129 for(var i = 0, len = el.length; i < len; i++) {
18130 this.register(el[i]);
18136 Roo.dd.ScrollManager.els = els;
18140 * Unregisters overflow element(s) so they are no longer scrolled
18141 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
18143 unregister : function(el){
18144 if(el instanceof Array){
18145 for(var i = 0, len = el.length; i < len; i++) {
18146 this.unregister(el[i]);
18155 * The number of pixels from the edge of a container the pointer needs to be to
18156 * trigger scrolling (defaults to 25)
18162 * The number of pixels to scroll in each scroll increment (defaults to 50)
18168 * The frequency of scrolls in milliseconds (defaults to 500)
18174 * True to animate the scroll (defaults to true)
18180 * The animation duration in seconds -
18181 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
18187 * Manually trigger a cache refresh.
18189 refreshCache : function(){
18190 for(var id in els){
18191 if(typeof els[id] == 'object'){ // for people extending the object prototype
18192 els[id]._region = els[id].getRegion();
18199 * Ext JS Library 1.1.1
18200 * Copyright(c) 2006-2007, Ext JS, LLC.
18202 * Originally Released Under LGPL - original licence link has changed is not relivant.
18205 * <script type="text/javascript">
18210 * @class Roo.dd.Registry
18211 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
18212 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
18215 Roo.dd.Registry = function(){
18218 var autoIdSeed = 0;
18220 var getId = function(el, autogen){
18221 if(typeof el == "string"){
18225 if(!id && autogen !== false){
18226 id = "roodd-" + (++autoIdSeed);
18234 * Register a drag drop element
18235 * @param {String|HTMLElement} element The id or DOM node to register
18236 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
18237 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
18238 * knows how to interpret, plus there are some specific properties known to the Registry that should be
18239 * populated in the data object (if applicable):
18241 Value Description<br />
18242 --------- ------------------------------------------<br />
18243 handles Array of DOM nodes that trigger dragging<br />
18244 for the element being registered<br />
18245 isHandle True if the element passed in triggers<br />
18246 dragging itself, else false
18249 register : function(el, data){
18251 if(typeof el == "string"){
18252 el = document.getElementById(el);
18255 elements[getId(el)] = data;
18256 if(data.isHandle !== false){
18257 handles[data.ddel.id] = data;
18260 var hs = data.handles;
18261 for(var i = 0, len = hs.length; i < len; i++){
18262 handles[getId(hs[i])] = data;
18268 * Unregister a drag drop element
18269 * @param {String|HTMLElement} element The id or DOM node to unregister
18271 unregister : function(el){
18272 var id = getId(el, false);
18273 var data = elements[id];
18275 delete elements[id];
18277 var hs = data.handles;
18278 for(var i = 0, len = hs.length; i < len; i++){
18279 delete handles[getId(hs[i], false)];
18286 * Returns the handle registered for a DOM Node by id
18287 * @param {String|HTMLElement} id The DOM node or id to look up
18288 * @return {Object} handle The custom handle data
18290 getHandle : function(id){
18291 if(typeof id != "string"){ // must be element?
18294 return handles[id];
18298 * Returns the handle that is registered for the DOM node that is the target of the event
18299 * @param {Event} e The event
18300 * @return {Object} handle The custom handle data
18302 getHandleFromEvent : function(e){
18303 var t = Roo.lib.Event.getTarget(e);
18304 return t ? handles[t.id] : null;
18308 * Returns a custom data object that is registered for a DOM node by id
18309 * @param {String|HTMLElement} id The DOM node or id to look up
18310 * @return {Object} data The custom data
18312 getTarget : function(id){
18313 if(typeof id != "string"){ // must be element?
18316 return elements[id];
18320 * Returns a custom data object that is registered for the DOM node that is the target of the event
18321 * @param {Event} e The event
18322 * @return {Object} data The custom data
18324 getTargetFromEvent : function(e){
18325 var t = Roo.lib.Event.getTarget(e);
18326 return t ? elements[t.id] || handles[t.id] : null;
18331 * Ext JS Library 1.1.1
18332 * Copyright(c) 2006-2007, Ext JS, LLC.
18334 * Originally Released Under LGPL - original licence link has changed is not relivant.
18337 * <script type="text/javascript">
18342 * @class Roo.dd.StatusProxy
18343 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
18344 * default drag proxy used by all Roo.dd components.
18346 * @param {Object} config
18348 Roo.dd.StatusProxy = function(config){
18349 Roo.apply(this, config);
18350 this.id = this.id || Roo.id();
18351 this.el = new Roo.Layer({
18353 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
18354 {tag: "div", cls: "x-dd-drop-icon"},
18355 {tag: "div", cls: "x-dd-drag-ghost"}
18358 shadow: !config || config.shadow !== false
18360 this.ghost = Roo.get(this.el.dom.childNodes[1]);
18361 this.dropStatus = this.dropNotAllowed;
18364 Roo.dd.StatusProxy.prototype = {
18366 * @cfg {String} dropAllowed
18367 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
18369 dropAllowed : "x-dd-drop-ok",
18371 * @cfg {String} dropNotAllowed
18372 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
18374 dropNotAllowed : "x-dd-drop-nodrop",
18377 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
18378 * over the current target element.
18379 * @param {String} cssClass The css class for the new drop status indicator image
18381 setStatus : function(cssClass){
18382 cssClass = cssClass || this.dropNotAllowed;
18383 if(this.dropStatus != cssClass){
18384 this.el.replaceClass(this.dropStatus, cssClass);
18385 this.dropStatus = cssClass;
18390 * Resets the status indicator to the default dropNotAllowed value
18391 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
18393 reset : function(clearGhost){
18394 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
18395 this.dropStatus = this.dropNotAllowed;
18397 this.ghost.update("");
18402 * Updates the contents of the ghost element
18403 * @param {String} html The html that will replace the current innerHTML of the ghost element
18405 update : function(html){
18406 if(typeof html == "string"){
18407 this.ghost.update(html);
18409 this.ghost.update("");
18410 html.style.margin = "0";
18411 this.ghost.dom.appendChild(html);
18413 // ensure float = none set?? cant remember why though.
18414 var el = this.ghost.dom.firstChild;
18416 Roo.fly(el).setStyle('float', 'none');
18421 * Returns the underlying proxy {@link Roo.Layer}
18422 * @return {Roo.Layer} el
18424 getEl : function(){
18429 * Returns the ghost element
18430 * @return {Roo.Element} el
18432 getGhost : function(){
18438 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
18440 hide : function(clear){
18448 * Stops the repair animation if it's currently running
18451 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
18457 * Displays this proxy
18464 * Force the Layer to sync its shadow and shim positions to the element
18471 * Causes the proxy to return to its position of origin via an animation. Should be called after an
18472 * invalid drop operation by the item being dragged.
18473 * @param {Array} xy The XY position of the element ([x, y])
18474 * @param {Function} callback The function to call after the repair is complete
18475 * @param {Object} scope The scope in which to execute the callback
18477 repair : function(xy, callback, scope){
18478 this.callback = callback;
18479 this.scope = scope;
18480 if(xy && this.animRepair !== false){
18481 this.el.addClass("x-dd-drag-repair");
18482 this.el.hideUnders(true);
18483 this.anim = this.el.shift({
18484 duration: this.repairDuration || .5,
18488 callback: this.afterRepair,
18492 this.afterRepair();
18497 afterRepair : function(){
18499 if(typeof this.callback == "function"){
18500 this.callback.call(this.scope || this);
18502 this.callback = null;
18507 * Ext JS Library 1.1.1
18508 * Copyright(c) 2006-2007, Ext JS, LLC.
18510 * Originally Released Under LGPL - original licence link has changed is not relivant.
18513 * <script type="text/javascript">
18517 * @class Roo.dd.DragSource
18518 * @extends Roo.dd.DDProxy
18519 * A simple class that provides the basic implementation needed to make any element draggable.
18521 * @param {String/HTMLElement/Element} el The container element
18522 * @param {Object} config
18524 Roo.dd.DragSource = function(el, config){
18525 this.el = Roo.get(el);
18526 this.dragData = {};
18528 Roo.apply(this, config);
18531 this.proxy = new Roo.dd.StatusProxy();
18534 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18535 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18537 this.dragging = false;
18540 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18542 * @cfg {String} dropAllowed
18543 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18545 dropAllowed : "x-dd-drop-ok",
18547 * @cfg {String} dropNotAllowed
18548 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18550 dropNotAllowed : "x-dd-drop-nodrop",
18553 * Returns the data object associated with this drag source
18554 * @return {Object} data An object containing arbitrary data
18556 getDragData : function(e){
18557 return this.dragData;
18561 onDragEnter : function(e, id){
18562 var target = Roo.dd.DragDropMgr.getDDById(id);
18563 this.cachedTarget = target;
18564 if(this.beforeDragEnter(target, e, id) !== false){
18565 if(target.isNotifyTarget){
18566 var status = target.notifyEnter(this, e, this.dragData);
18567 this.proxy.setStatus(status);
18569 this.proxy.setStatus(this.dropAllowed);
18572 if(this.afterDragEnter){
18574 * An empty function by default, but provided so that you can perform a custom action
18575 * when the dragged item enters the drop target by providing an implementation.
18576 * @param {Roo.dd.DragDrop} target The drop target
18577 * @param {Event} e The event object
18578 * @param {String} id The id of the dragged element
18579 * @method afterDragEnter
18581 this.afterDragEnter(target, e, id);
18587 * An empty function by default, but provided so that you can perform a custom action
18588 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18589 * @param {Roo.dd.DragDrop} target The drop target
18590 * @param {Event} e The event object
18591 * @param {String} id The id of the dragged element
18592 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18594 beforeDragEnter : function(target, e, id){
18599 alignElWithMouse: function() {
18600 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18605 onDragOver : function(e, id){
18606 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18607 if(this.beforeDragOver(target, e, id) !== false){
18608 if(target.isNotifyTarget){
18609 var status = target.notifyOver(this, e, this.dragData);
18610 this.proxy.setStatus(status);
18613 if(this.afterDragOver){
18615 * An empty function by default, but provided so that you can perform a custom action
18616 * while the dragged item is over the drop target by providing an implementation.
18617 * @param {Roo.dd.DragDrop} target The drop target
18618 * @param {Event} e The event object
18619 * @param {String} id The id of the dragged element
18620 * @method afterDragOver
18622 this.afterDragOver(target, e, id);
18628 * An empty function by default, but provided so that you can perform a custom action
18629 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18630 * @param {Roo.dd.DragDrop} target The drop target
18631 * @param {Event} e The event object
18632 * @param {String} id The id of the dragged element
18633 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18635 beforeDragOver : function(target, e, id){
18640 onDragOut : function(e, id){
18641 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18642 if(this.beforeDragOut(target, e, id) !== false){
18643 if(target.isNotifyTarget){
18644 target.notifyOut(this, e, this.dragData);
18646 this.proxy.reset();
18647 if(this.afterDragOut){
18649 * An empty function by default, but provided so that you can perform a custom action
18650 * after the dragged item is dragged out of the target without dropping.
18651 * @param {Roo.dd.DragDrop} target The drop target
18652 * @param {Event} e The event object
18653 * @param {String} id The id of the dragged element
18654 * @method afterDragOut
18656 this.afterDragOut(target, e, id);
18659 this.cachedTarget = null;
18663 * An empty function by default, but provided so that you can perform a custom action before the dragged
18664 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18665 * @param {Roo.dd.DragDrop} target The drop target
18666 * @param {Event} e The event object
18667 * @param {String} id The id of the dragged element
18668 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18670 beforeDragOut : function(target, e, id){
18675 onDragDrop : function(e, id){
18676 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18677 if(this.beforeDragDrop(target, e, id) !== false){
18678 if(target.isNotifyTarget){
18679 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18680 this.onValidDrop(target, e, id);
18682 this.onInvalidDrop(target, e, id);
18685 this.onValidDrop(target, e, id);
18688 if(this.afterDragDrop){
18690 * An empty function by default, but provided so that you can perform a custom action
18691 * after a valid drag drop has occurred by providing an implementation.
18692 * @param {Roo.dd.DragDrop} target The drop target
18693 * @param {Event} e The event object
18694 * @param {String} id The id of the dropped element
18695 * @method afterDragDrop
18697 this.afterDragDrop(target, e, id);
18700 delete this.cachedTarget;
18704 * An empty function by default, but provided so that you can perform a custom action before the dragged
18705 * item is dropped onto the target and optionally cancel the onDragDrop.
18706 * @param {Roo.dd.DragDrop} target The drop target
18707 * @param {Event} e The event object
18708 * @param {String} id The id of the dragged element
18709 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18711 beforeDragDrop : function(target, e, id){
18716 onValidDrop : function(target, e, id){
18718 if(this.afterValidDrop){
18720 * An empty function by default, but provided so that you can perform a custom action
18721 * after a valid drop has occurred by providing an implementation.
18722 * @param {Object} target The target DD
18723 * @param {Event} e The event object
18724 * @param {String} id The id of the dropped element
18725 * @method afterInvalidDrop
18727 this.afterValidDrop(target, e, id);
18732 getRepairXY : function(e, data){
18733 return this.el.getXY();
18737 onInvalidDrop : function(target, e, id){
18738 this.beforeInvalidDrop(target, e, id);
18739 if(this.cachedTarget){
18740 if(this.cachedTarget.isNotifyTarget){
18741 this.cachedTarget.notifyOut(this, e, this.dragData);
18743 this.cacheTarget = null;
18745 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18747 if(this.afterInvalidDrop){
18749 * An empty function by default, but provided so that you can perform a custom action
18750 * after an invalid drop has occurred by providing an implementation.
18751 * @param {Event} e The event object
18752 * @param {String} id The id of the dropped element
18753 * @method afterInvalidDrop
18755 this.afterInvalidDrop(e, id);
18760 afterRepair : function(){
18762 this.el.highlight(this.hlColor || "c3daf9");
18764 this.dragging = false;
18768 * An empty function by default, but provided so that you can perform a custom action after an invalid
18769 * drop has occurred.
18770 * @param {Roo.dd.DragDrop} target The drop target
18771 * @param {Event} e The event object
18772 * @param {String} id The id of the dragged element
18773 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18775 beforeInvalidDrop : function(target, e, id){
18780 handleMouseDown : function(e){
18781 if(this.dragging) {
18784 var data = this.getDragData(e);
18785 if(data && this.onBeforeDrag(data, e) !== false){
18786 this.dragData = data;
18788 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18793 * An empty function by default, but provided so that you can perform a custom action before the initial
18794 * drag event begins and optionally cancel it.
18795 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18796 * @param {Event} e The event object
18797 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18799 onBeforeDrag : function(data, e){
18804 * An empty function by default, but provided so that you can perform a custom action once the initial
18805 * drag event has begun. The drag cannot be canceled from this function.
18806 * @param {Number} x The x position of the click on the dragged object
18807 * @param {Number} y The y position of the click on the dragged object
18809 onStartDrag : Roo.emptyFn,
18811 // private - YUI override
18812 startDrag : function(x, y){
18813 this.proxy.reset();
18814 this.dragging = true;
18815 this.proxy.update("");
18816 this.onInitDrag(x, y);
18821 onInitDrag : function(x, y){
18822 var clone = this.el.dom.cloneNode(true);
18823 clone.id = Roo.id(); // prevent duplicate ids
18824 this.proxy.update(clone);
18825 this.onStartDrag(x, y);
18830 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18831 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18833 getProxy : function(){
18838 * Hides the drag source's {@link Roo.dd.StatusProxy}
18840 hideProxy : function(){
18842 this.proxy.reset(true);
18843 this.dragging = false;
18847 triggerCacheRefresh : function(){
18848 Roo.dd.DDM.refreshCache(this.groups);
18851 // private - override to prevent hiding
18852 b4EndDrag: function(e) {
18855 // private - override to prevent moving
18856 endDrag : function(e){
18857 this.onEndDrag(this.dragData, e);
18861 onEndDrag : function(data, e){
18864 // private - pin to cursor
18865 autoOffset : function(x, y) {
18866 this.setDelta(-12, -20);
18870 * Ext JS Library 1.1.1
18871 * Copyright(c) 2006-2007, Ext JS, LLC.
18873 * Originally Released Under LGPL - original licence link has changed is not relivant.
18876 * <script type="text/javascript">
18881 * @class Roo.dd.DropTarget
18882 * @extends Roo.dd.DDTarget
18883 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18884 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18886 * @param {String/HTMLElement/Element} el The container element
18887 * @param {Object} config
18889 Roo.dd.DropTarget = function(el, config){
18890 this.el = Roo.get(el);
18892 var listeners = false; ;
18893 if (config && config.listeners) {
18894 listeners= config.listeners;
18895 delete config.listeners;
18897 Roo.apply(this, config);
18899 if(this.containerScroll){
18900 Roo.dd.ScrollManager.register(this.el);
18904 * @scope Roo.dd.DropTarget
18909 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18910 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18911 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18913 * IMPORTANT : it should set this.overClass and this.dropAllowed
18915 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18916 * @param {Event} e The event
18917 * @param {Object} data An object containing arbitrary data supplied by the drag source
18923 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18924 * This method will be called on every mouse movement while the drag source is over the drop target.
18925 * This default implementation simply returns the dropAllowed config value.
18927 * IMPORTANT : it should set this.dropAllowed
18929 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18930 * @param {Event} e The event
18931 * @param {Object} data An object containing arbitrary data supplied by the drag source
18937 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18938 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18939 * overClass (if any) from the drop element.
18941 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18942 * @param {Event} e The event
18943 * @param {Object} data An object containing arbitrary data supplied by the drag source
18949 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18950 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18951 * implementation that does something to process the drop event and returns true so that the drag source's
18952 * repair action does not run.
18954 * IMPORTANT : it should set this.success
18956 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18957 * @param {Event} e The event
18958 * @param {Object} data An object containing arbitrary data supplied by the drag source
18964 Roo.dd.DropTarget.superclass.constructor.call( this,
18966 this.ddGroup || this.group,
18969 listeners : listeners || {}
18977 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18979 * @cfg {String} overClass
18980 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18983 * @cfg {String} ddGroup
18984 * The drag drop group to handle drop events for
18988 * @cfg {String} dropAllowed
18989 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18991 dropAllowed : "x-dd-drop-ok",
18993 * @cfg {String} dropNotAllowed
18994 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18996 dropNotAllowed : "x-dd-drop-nodrop",
18998 * @cfg {boolean} success
18999 * set this after drop listener..
19003 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
19004 * if the drop point is valid for over/enter..
19011 isNotifyTarget : true,
19016 notifyEnter : function(dd, e, data)
19019 this.fireEvent('enter', dd, e, data);
19020 if(this.overClass){
19021 this.el.addClass(this.overClass);
19023 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19024 this.valid ? this.dropAllowed : this.dropNotAllowed
19031 notifyOver : function(dd, e, data)
19034 this.fireEvent('over', dd, e, data);
19035 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19036 this.valid ? this.dropAllowed : this.dropNotAllowed
19043 notifyOut : function(dd, e, data)
19045 this.fireEvent('out', dd, e, data);
19046 if(this.overClass){
19047 this.el.removeClass(this.overClass);
19054 notifyDrop : function(dd, e, data)
19056 this.success = false;
19057 this.fireEvent('drop', dd, e, data);
19058 return this.success;
19062 * Ext JS Library 1.1.1
19063 * Copyright(c) 2006-2007, Ext JS, LLC.
19065 * Originally Released Under LGPL - original licence link has changed is not relivant.
19068 * <script type="text/javascript">
19073 * @class Roo.dd.DragZone
19074 * @extends Roo.dd.DragSource
19075 * This class provides a container DD instance that proxies for multiple child node sources.<br />
19076 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
19078 * @param {String/HTMLElement/Element} el The container element
19079 * @param {Object} config
19081 Roo.dd.DragZone = function(el, config){
19082 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
19083 if(this.containerScroll){
19084 Roo.dd.ScrollManager.register(this.el);
19088 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
19090 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
19091 * for auto scrolling during drag operations.
19094 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
19095 * method after a failed drop (defaults to "c3daf9" - light blue)
19099 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
19100 * for a valid target to drag based on the mouse down. Override this method
19101 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
19102 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
19103 * @param {EventObject} e The mouse down event
19104 * @return {Object} The dragData
19106 getDragData : function(e){
19107 return Roo.dd.Registry.getHandleFromEvent(e);
19111 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
19112 * this.dragData.ddel
19113 * @param {Number} x The x position of the click on the dragged object
19114 * @param {Number} y The y position of the click on the dragged object
19115 * @return {Boolean} true to continue the drag, false to cancel
19117 onInitDrag : function(x, y){
19118 this.proxy.update(this.dragData.ddel.cloneNode(true));
19119 this.onStartDrag(x, y);
19124 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
19126 afterRepair : function(){
19128 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
19130 this.dragging = false;
19134 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
19135 * the XY of this.dragData.ddel
19136 * @param {EventObject} e The mouse up event
19137 * @return {Array} The xy location (e.g. [100, 200])
19139 getRepairXY : function(e){
19140 return Roo.Element.fly(this.dragData.ddel).getXY();
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">
19153 * @class Roo.dd.DropZone
19154 * @extends Roo.dd.DropTarget
19155 * This class provides a container DD instance that proxies for multiple child node targets.<br />
19156 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
19158 * @param {String/HTMLElement/Element} el The container element
19159 * @param {Object} config
19161 Roo.dd.DropZone = function(el, config){
19162 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
19165 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
19167 * Returns a custom data object associated with the DOM node that is the target of the event. By default
19168 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
19169 * provide your own custom lookup.
19170 * @param {Event} e The event
19171 * @return {Object} data The custom data
19173 getTargetFromEvent : function(e){
19174 return Roo.dd.Registry.getTargetFromEvent(e);
19178 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
19179 * that it has registered. This method has no default implementation and should be overridden to provide
19180 * node-specific processing if necessary.
19181 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19182 * {@link #getTargetFromEvent} for this node)
19183 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19184 * @param {Event} e The event
19185 * @param {Object} data An object containing arbitrary data supplied by the drag source
19187 onNodeEnter : function(n, dd, e, data){
19192 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
19193 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
19194 * overridden to provide the proper feedback.
19195 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19196 * {@link #getTargetFromEvent} for this node)
19197 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19198 * @param {Event} e The event
19199 * @param {Object} data An object containing arbitrary data supplied by the drag source
19200 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19201 * underlying {@link Roo.dd.StatusProxy} can be updated
19203 onNodeOver : function(n, dd, e, data){
19204 return this.dropAllowed;
19208 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
19209 * the drop node without dropping. This method has no default implementation and should be overridden to provide
19210 * node-specific processing if necessary.
19211 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19212 * {@link #getTargetFromEvent} for this node)
19213 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19214 * @param {Event} e The event
19215 * @param {Object} data An object containing arbitrary data supplied by the drag source
19217 onNodeOut : function(n, dd, e, data){
19222 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
19223 * the drop node. The default implementation returns false, so it should be overridden to provide the
19224 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
19225 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19226 * {@link #getTargetFromEvent} for this node)
19227 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19228 * @param {Event} e The event
19229 * @param {Object} data An object containing arbitrary data supplied by the drag source
19230 * @return {Boolean} True if the drop was valid, else false
19232 onNodeDrop : function(n, dd, e, data){
19237 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
19238 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
19239 * it should be overridden to provide the proper feedback if necessary.
19240 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19241 * @param {Event} e The event
19242 * @param {Object} data An object containing arbitrary data supplied by the drag source
19243 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19244 * underlying {@link Roo.dd.StatusProxy} can be updated
19246 onContainerOver : function(dd, e, data){
19247 return this.dropNotAllowed;
19251 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
19252 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
19253 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
19254 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
19255 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19256 * @param {Event} e The event
19257 * @param {Object} data An object containing arbitrary data supplied by the drag source
19258 * @return {Boolean} True if the drop was valid, else false
19260 onContainerDrop : function(dd, e, data){
19265 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
19266 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
19267 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
19268 * you should override this method and provide a custom implementation.
19269 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19270 * @param {Event} e The event
19271 * @param {Object} data An object containing arbitrary data supplied by the drag source
19272 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19273 * underlying {@link Roo.dd.StatusProxy} can be updated
19275 notifyEnter : function(dd, e, data){
19276 return this.dropNotAllowed;
19280 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
19281 * This method will be called on every mouse movement while the drag source is over the drop zone.
19282 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
19283 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
19284 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
19285 * registered node, it will call {@link #onContainerOver}.
19286 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19287 * @param {Event} e The event
19288 * @param {Object} data An object containing arbitrary data supplied by the drag source
19289 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19290 * underlying {@link Roo.dd.StatusProxy} can be updated
19292 notifyOver : function(dd, e, data){
19293 var n = this.getTargetFromEvent(e);
19294 if(!n){ // not over valid drop target
19295 if(this.lastOverNode){
19296 this.onNodeOut(this.lastOverNode, dd, e, data);
19297 this.lastOverNode = null;
19299 return this.onContainerOver(dd, e, data);
19301 if(this.lastOverNode != n){
19302 if(this.lastOverNode){
19303 this.onNodeOut(this.lastOverNode, dd, e, data);
19305 this.onNodeEnter(n, dd, e, data);
19306 this.lastOverNode = n;
19308 return this.onNodeOver(n, dd, e, data);
19312 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
19313 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
19314 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
19315 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19316 * @param {Event} e The event
19317 * @param {Object} data An object containing arbitrary data supplied by the drag zone
19319 notifyOut : function(dd, e, data){
19320 if(this.lastOverNode){
19321 this.onNodeOut(this.lastOverNode, dd, e, data);
19322 this.lastOverNode = null;
19327 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
19328 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
19329 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
19330 * otherwise it will call {@link #onContainerDrop}.
19331 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19332 * @param {Event} e The event
19333 * @param {Object} data An object containing arbitrary data supplied by the drag source
19334 * @return {Boolean} True if the drop was valid, else false
19336 notifyDrop : function(dd, e, data){
19337 if(this.lastOverNode){
19338 this.onNodeOut(this.lastOverNode, dd, e, data);
19339 this.lastOverNode = null;
19341 var n = this.getTargetFromEvent(e);
19343 this.onNodeDrop(n, dd, e, data) :
19344 this.onContainerDrop(dd, e, data);
19348 triggerCacheRefresh : function(){
19349 Roo.dd.DDM.refreshCache(this.groups);
19353 * Ext JS Library 1.1.1
19354 * Copyright(c) 2006-2007, Ext JS, LLC.
19356 * Originally Released Under LGPL - original licence link has changed is not relivant.
19359 * <script type="text/javascript">
19364 * @class Roo.data.SortTypes
19366 * Defines the default sorting (casting?) comparison functions used when sorting data.
19368 Roo.data.SortTypes = {
19370 * Default sort that does nothing
19371 * @param {Mixed} s The value being converted
19372 * @return {Mixed} The comparison value
19374 none : function(s){
19379 * The regular expression used to strip tags
19383 stripTagsRE : /<\/?[^>]+>/gi,
19386 * Strips all HTML tags to sort on text only
19387 * @param {Mixed} s The value being converted
19388 * @return {String} The comparison value
19390 asText : function(s){
19391 return String(s).replace(this.stripTagsRE, "");
19395 * Strips all HTML tags to sort on text only - Case insensitive
19396 * @param {Mixed} s The value being converted
19397 * @return {String} The comparison value
19399 asUCText : function(s){
19400 return String(s).toUpperCase().replace(this.stripTagsRE, "");
19404 * Case insensitive string
19405 * @param {Mixed} s The value being converted
19406 * @return {String} The comparison value
19408 asUCString : function(s) {
19409 return String(s).toUpperCase();
19414 * @param {Mixed} s The value being converted
19415 * @return {Number} The comparison value
19417 asDate : function(s) {
19421 if(s instanceof Date){
19422 return s.getTime();
19424 return Date.parse(String(s));
19429 * @param {Mixed} s The value being converted
19430 * @return {Float} The comparison value
19432 asFloat : function(s) {
19433 var val = parseFloat(String(s).replace(/,/g, ""));
19434 if(isNaN(val)) val = 0;
19440 * @param {Mixed} s The value being converted
19441 * @return {Number} The comparison value
19443 asInt : function(s) {
19444 var val = parseInt(String(s).replace(/,/g, ""));
19445 if(isNaN(val)) val = 0;
19450 * Ext JS Library 1.1.1
19451 * Copyright(c) 2006-2007, Ext JS, LLC.
19453 * Originally Released Under LGPL - original licence link has changed is not relivant.
19456 * <script type="text/javascript">
19460 * @class Roo.data.Record
19461 * Instances of this class encapsulate both record <em>definition</em> information, and record
19462 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
19463 * to access Records cached in an {@link Roo.data.Store} object.<br>
19465 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
19466 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
19469 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
19471 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
19472 * {@link #create}. The parameters are the same.
19473 * @param {Array} data An associative Array of data values keyed by the field name.
19474 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
19475 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
19476 * not specified an integer id is generated.
19478 Roo.data.Record = function(data, id){
19479 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19484 * Generate a constructor for a specific record layout.
19485 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19486 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19487 * Each field definition object may contain the following properties: <ul>
19488 * <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,
19489 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19490 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19491 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19492 * is being used, then this is a string containing the javascript expression to reference the data relative to
19493 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19494 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19495 * this may be omitted.</p></li>
19496 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19497 * <ul><li>auto (Default, implies no conversion)</li>
19502 * <li>date</li></ul></p></li>
19503 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19504 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19505 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19506 * by the Reader into an object that will be stored in the Record. It is passed the
19507 * following parameters:<ul>
19508 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19510 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19512 * <br>usage:<br><pre><code>
19513 var TopicRecord = Roo.data.Record.create(
19514 {name: 'title', mapping: 'topic_title'},
19515 {name: 'author', mapping: 'username'},
19516 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19517 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19518 {name: 'lastPoster', mapping: 'user2'},
19519 {name: 'excerpt', mapping: 'post_text'}
19522 var myNewRecord = new TopicRecord({
19523 title: 'Do my job please',
19526 lastPost: new Date(),
19527 lastPoster: 'Animal',
19528 excerpt: 'No way dude!'
19530 myStore.add(myNewRecord);
19535 Roo.data.Record.create = function(o){
19536 var f = function(){
19537 f.superclass.constructor.apply(this, arguments);
19539 Roo.extend(f, Roo.data.Record);
19540 var p = f.prototype;
19541 p.fields = new Roo.util.MixedCollection(false, function(field){
19544 for(var i = 0, len = o.length; i < len; i++){
19545 p.fields.add(new Roo.data.Field(o[i]));
19547 f.getField = function(name){
19548 return p.fields.get(name);
19553 Roo.data.Record.AUTO_ID = 1000;
19554 Roo.data.Record.EDIT = 'edit';
19555 Roo.data.Record.REJECT = 'reject';
19556 Roo.data.Record.COMMIT = 'commit';
19558 Roo.data.Record.prototype = {
19560 * Readonly flag - true if this record has been modified.
19569 join : function(store){
19570 this.store = store;
19574 * Set the named field to the specified value.
19575 * @param {String} name The name of the field to set.
19576 * @param {Object} value The value to set the field to.
19578 set : function(name, value){
19579 if(this.data[name] == value){
19583 if(!this.modified){
19584 this.modified = {};
19586 if(typeof this.modified[name] == 'undefined'){
19587 this.modified[name] = this.data[name];
19589 this.data[name] = value;
19590 if(!this.editing && this.store){
19591 this.store.afterEdit(this);
19596 * Get the value of the named field.
19597 * @param {String} name The name of the field to get the value of.
19598 * @return {Object} The value of the field.
19600 get : function(name){
19601 return this.data[name];
19605 beginEdit : function(){
19606 this.editing = true;
19607 this.modified = {};
19611 cancelEdit : function(){
19612 this.editing = false;
19613 delete this.modified;
19617 endEdit : function(){
19618 this.editing = false;
19619 if(this.dirty && this.store){
19620 this.store.afterEdit(this);
19625 * Usually called by the {@link Roo.data.Store} which owns the Record.
19626 * Rejects all changes made to the Record since either creation, or the last commit operation.
19627 * Modified fields are reverted to their original values.
19629 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19630 * of reject operations.
19632 reject : function(){
19633 var m = this.modified;
19635 if(typeof m[n] != "function"){
19636 this.data[n] = m[n];
19639 this.dirty = false;
19640 delete this.modified;
19641 this.editing = false;
19643 this.store.afterReject(this);
19648 * Usually called by the {@link Roo.data.Store} which owns the Record.
19649 * Commits all changes made to the Record since either creation, or the last commit operation.
19651 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19652 * of commit operations.
19654 commit : function(){
19655 this.dirty = false;
19656 delete this.modified;
19657 this.editing = false;
19659 this.store.afterCommit(this);
19664 hasError : function(){
19665 return this.error != null;
19669 clearError : function(){
19674 * Creates a copy of this record.
19675 * @param {String} id (optional) A new record id if you don't want to use this record's id
19678 copy : function(newId) {
19679 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19683 * Ext JS Library 1.1.1
19684 * Copyright(c) 2006-2007, Ext JS, LLC.
19686 * Originally Released Under LGPL - original licence link has changed is not relivant.
19689 * <script type="text/javascript">
19695 * @class Roo.data.Store
19696 * @extends Roo.util.Observable
19697 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19698 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19700 * 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
19701 * has no knowledge of the format of the data returned by the Proxy.<br>
19703 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19704 * instances from the data object. These records are cached and made available through accessor functions.
19706 * Creates a new Store.
19707 * @param {Object} config A config object containing the objects needed for the Store to access data,
19708 * and read the data into Records.
19710 Roo.data.Store = function(config){
19711 this.data = new Roo.util.MixedCollection(false);
19712 this.data.getKey = function(o){
19715 this.baseParams = {};
19717 this.paramNames = {
19722 "multisort" : "_multisort"
19725 if(config && config.data){
19726 this.inlineData = config.data;
19727 delete config.data;
19730 Roo.apply(this, config);
19732 if(this.reader){ // reader passed
19733 this.reader = Roo.factory(this.reader, Roo.data);
19734 this.reader.xmodule = this.xmodule || false;
19735 if(!this.recordType){
19736 this.recordType = this.reader.recordType;
19738 if(this.reader.onMetaChange){
19739 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19743 if(this.recordType){
19744 this.fields = this.recordType.prototype.fields;
19746 this.modified = [];
19750 * @event datachanged
19751 * Fires when the data cache has changed, and a widget which is using this Store
19752 * as a Record cache should refresh its view.
19753 * @param {Store} this
19755 datachanged : true,
19757 * @event metachange
19758 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19759 * @param {Store} this
19760 * @param {Object} meta The JSON metadata
19765 * Fires when Records have been added to the Store
19766 * @param {Store} this
19767 * @param {Roo.data.Record[]} records The array of Records added
19768 * @param {Number} index The index at which the record(s) were added
19773 * Fires when a Record has been removed from the Store
19774 * @param {Store} this
19775 * @param {Roo.data.Record} record The Record that was removed
19776 * @param {Number} index The index at which the record was removed
19781 * Fires when a Record has been updated
19782 * @param {Store} this
19783 * @param {Roo.data.Record} record The Record that was updated
19784 * @param {String} operation The update operation being performed. Value may be one of:
19786 Roo.data.Record.EDIT
19787 Roo.data.Record.REJECT
19788 Roo.data.Record.COMMIT
19794 * Fires when the data cache has been cleared.
19795 * @param {Store} this
19799 * @event beforeload
19800 * Fires before a request is made for a new data object. If the beforeload handler returns false
19801 * the load action will be canceled.
19802 * @param {Store} this
19803 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19808 * Fires after a new set of Records has been loaded.
19809 * @param {Store} this
19810 * @param {Roo.data.Record[]} records The Records that were loaded
19811 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19815 * @event loadexception
19816 * Fires if an exception occurs in the Proxy during loading.
19817 * Called with the signature of the Proxy's "loadexception" event.
19818 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19821 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19822 * @param {Object} load options
19823 * @param {Object} jsonData from your request (normally this contains the Exception)
19825 loadexception : true
19829 this.proxy = Roo.factory(this.proxy, Roo.data);
19830 this.proxy.xmodule = this.xmodule || false;
19831 this.relayEvents(this.proxy, ["loadexception"]);
19833 this.sortToggle = {};
19834 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19836 Roo.data.Store.superclass.constructor.call(this);
19838 if(this.inlineData){
19839 this.loadData(this.inlineData);
19840 delete this.inlineData;
19843 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19845 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19846 * without a remote query - used by combo/forms at present.
19850 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19853 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19856 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19857 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19860 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19861 * on any HTTP request
19864 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19867 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19871 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19872 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19874 remoteSort : false,
19877 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19878 * loaded or when a record is removed. (defaults to false).
19880 pruneModifiedRecords : false,
19883 lastOptions : null,
19886 * Add Records to the Store and fires the add event.
19887 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19889 add : function(records){
19890 records = [].concat(records);
19891 for(var i = 0, len = records.length; i < len; i++){
19892 records[i].join(this);
19894 var index = this.data.length;
19895 this.data.addAll(records);
19896 this.fireEvent("add", this, records, index);
19900 * Remove a Record from the Store and fires the remove event.
19901 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19903 remove : function(record){
19904 var index = this.data.indexOf(record);
19905 this.data.removeAt(index);
19906 if(this.pruneModifiedRecords){
19907 this.modified.remove(record);
19909 this.fireEvent("remove", this, record, index);
19913 * Remove all Records from the Store and fires the clear event.
19915 removeAll : function(){
19917 if(this.pruneModifiedRecords){
19918 this.modified = [];
19920 this.fireEvent("clear", this);
19924 * Inserts Records to the Store at the given index and fires the add event.
19925 * @param {Number} index The start index at which to insert the passed Records.
19926 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19928 insert : function(index, records){
19929 records = [].concat(records);
19930 for(var i = 0, len = records.length; i < len; i++){
19931 this.data.insert(index, records[i]);
19932 records[i].join(this);
19934 this.fireEvent("add", this, records, index);
19938 * Get the index within the cache of the passed Record.
19939 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19940 * @return {Number} The index of the passed Record. Returns -1 if not found.
19942 indexOf : function(record){
19943 return this.data.indexOf(record);
19947 * Get the index within the cache of the Record with the passed id.
19948 * @param {String} id The id of the Record to find.
19949 * @return {Number} The index of the Record. Returns -1 if not found.
19951 indexOfId : function(id){
19952 return this.data.indexOfKey(id);
19956 * Get the Record with the specified id.
19957 * @param {String} id The id of the Record to find.
19958 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19960 getById : function(id){
19961 return this.data.key(id);
19965 * Get the Record at the specified index.
19966 * @param {Number} index The index of the Record to find.
19967 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19969 getAt : function(index){
19970 return this.data.itemAt(index);
19974 * Returns a range of Records between specified indices.
19975 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19976 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19977 * @return {Roo.data.Record[]} An array of Records
19979 getRange : function(start, end){
19980 return this.data.getRange(start, end);
19984 storeOptions : function(o){
19985 o = Roo.apply({}, o);
19988 this.lastOptions = o;
19992 * Loads the Record cache from the configured Proxy using the configured Reader.
19994 * If using remote paging, then the first load call must specify the <em>start</em>
19995 * and <em>limit</em> properties in the options.params property to establish the initial
19996 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19998 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19999 * and this call will return before the new data has been loaded. Perform any post-processing
20000 * in a callback function, or in a "load" event handler.</strong>
20002 * @param {Object} options An object containing properties which control loading options:<ul>
20003 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
20004 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
20005 * passed the following arguments:<ul>
20006 * <li>r : Roo.data.Record[]</li>
20007 * <li>options: Options object from the load call</li>
20008 * <li>success: Boolean success indicator</li></ul></li>
20009 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
20010 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
20013 load : function(options){
20014 options = options || {};
20015 if(this.fireEvent("beforeload", this, options) !== false){
20016 this.storeOptions(options);
20017 var p = Roo.apply(options.params || {}, this.baseParams);
20018 // if meta was not loaded from remote source.. try requesting it.
20019 if (!this.reader.metaFromRemote) {
20020 p._requestMeta = 1;
20022 if(this.sortInfo && this.remoteSort){
20023 var pn = this.paramNames;
20024 p[pn["sort"]] = this.sortInfo.field;
20025 p[pn["dir"]] = this.sortInfo.direction;
20027 if (this.multiSort) {
20028 var pn = this.paramNames;
20029 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
20032 this.proxy.load(p, this.reader, this.loadRecords, this, options);
20037 * Reloads the Record cache from the configured Proxy using the configured Reader and
20038 * the options from the last load operation performed.
20039 * @param {Object} options (optional) An object containing properties which may override the options
20040 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
20041 * the most recently used options are reused).
20043 reload : function(options){
20044 this.load(Roo.applyIf(options||{}, this.lastOptions));
20048 // Called as a callback by the Reader during a load operation.
20049 loadRecords : function(o, options, success){
20050 if(!o || success === false){
20051 if(success !== false){
20052 this.fireEvent("load", this, [], options);
20054 if(options.callback){
20055 options.callback.call(options.scope || this, [], options, false);
20059 // if data returned failure - throw an exception.
20060 if (o.success === false) {
20061 // show a message if no listener is registered.
20062 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
20063 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
20065 // loadmask wil be hooked into this..
20066 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
20069 var r = o.records, t = o.totalRecords || r.length;
20070 if(!options || options.add !== true){
20071 if(this.pruneModifiedRecords){
20072 this.modified = [];
20074 for(var i = 0, len = r.length; i < len; i++){
20078 this.data = this.snapshot;
20079 delete this.snapshot;
20082 this.data.addAll(r);
20083 this.totalLength = t;
20085 this.fireEvent("datachanged", this);
20087 this.totalLength = Math.max(t, this.data.length+r.length);
20090 this.fireEvent("load", this, r, options);
20091 if(options.callback){
20092 options.callback.call(options.scope || this, r, options, true);
20098 * Loads data from a passed data block. A Reader which understands the format of the data
20099 * must have been configured in the constructor.
20100 * @param {Object} data The data block from which to read the Records. The format of the data expected
20101 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
20102 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
20104 loadData : function(o, append){
20105 var r = this.reader.readRecords(o);
20106 this.loadRecords(r, {add: append}, true);
20110 * Gets the number of cached records.
20112 * <em>If using paging, this may not be the total size of the dataset. If the data object
20113 * used by the Reader contains the dataset size, then the getTotalCount() function returns
20114 * the data set size</em>
20116 getCount : function(){
20117 return this.data.length || 0;
20121 * Gets the total number of records in the dataset as returned by the server.
20123 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
20124 * the dataset size</em>
20126 getTotalCount : function(){
20127 return this.totalLength || 0;
20131 * Returns the sort state of the Store as an object with two properties:
20133 field {String} The name of the field by which the Records are sorted
20134 direction {String} The sort order, "ASC" or "DESC"
20137 getSortState : function(){
20138 return this.sortInfo;
20142 applySort : function(){
20143 if(this.sortInfo && !this.remoteSort){
20144 var s = this.sortInfo, f = s.field;
20145 var st = this.fields.get(f).sortType;
20146 var fn = function(r1, r2){
20147 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
20148 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
20150 this.data.sort(s.direction, fn);
20151 if(this.snapshot && this.snapshot != this.data){
20152 this.snapshot.sort(s.direction, fn);
20158 * Sets the default sort column and order to be used by the next load operation.
20159 * @param {String} fieldName The name of the field to sort by.
20160 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20162 setDefaultSort : function(field, dir){
20163 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
20167 * Sort the Records.
20168 * If remote sorting is used, the sort is performed on the server, and the cache is
20169 * reloaded. If local sorting is used, the cache is sorted internally.
20170 * @param {String} fieldName The name of the field to sort by.
20171 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20173 sort : function(fieldName, dir){
20174 var f = this.fields.get(fieldName);
20176 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
20178 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
20179 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
20184 this.sortToggle[f.name] = dir;
20185 this.sortInfo = {field: f.name, direction: dir};
20186 if(!this.remoteSort){
20188 this.fireEvent("datachanged", this);
20190 this.load(this.lastOptions);
20195 * Calls the specified function for each of the Records in the cache.
20196 * @param {Function} fn The function to call. The Record is passed as the first parameter.
20197 * Returning <em>false</em> aborts and exits the iteration.
20198 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
20200 each : function(fn, scope){
20201 this.data.each(fn, scope);
20205 * Gets all records modified since the last commit. Modified records are persisted across load operations
20206 * (e.g., during paging).
20207 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
20209 getModifiedRecords : function(){
20210 return this.modified;
20214 createFilterFn : function(property, value, anyMatch){
20215 if(!value.exec){ // not a regex
20216 value = String(value);
20217 if(value.length == 0){
20220 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
20222 return function(r){
20223 return value.test(r.data[property]);
20228 * Sums the value of <i>property</i> for each record between start and end and returns the result.
20229 * @param {String} property A field on your records
20230 * @param {Number} start The record index to start at (defaults to 0)
20231 * @param {Number} end The last record index to include (defaults to length - 1)
20232 * @return {Number} The sum
20234 sum : function(property, start, end){
20235 var rs = this.data.items, v = 0;
20236 start = start || 0;
20237 end = (end || end === 0) ? end : rs.length-1;
20239 for(var i = start; i <= end; i++){
20240 v += (rs[i].data[property] || 0);
20246 * Filter the records by a specified property.
20247 * @param {String} field A field on your records
20248 * @param {String/RegExp} value Either a string that the field
20249 * should start with or a RegExp to test against the field
20250 * @param {Boolean} anyMatch True to match any part not just the beginning
20252 filter : function(property, value, anyMatch){
20253 var fn = this.createFilterFn(property, value, anyMatch);
20254 return fn ? this.filterBy(fn) : this.clearFilter();
20258 * Filter by a function. The specified function will be called with each
20259 * record in this data source. If the function returns true the record is included,
20260 * otherwise it is filtered.
20261 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20262 * @param {Object} scope (optional) The scope of the function (defaults to this)
20264 filterBy : function(fn, scope){
20265 this.snapshot = this.snapshot || this.data;
20266 this.data = this.queryBy(fn, scope||this);
20267 this.fireEvent("datachanged", this);
20271 * Query the records by a specified property.
20272 * @param {String} field A field on your records
20273 * @param {String/RegExp} value Either a string that the field
20274 * should start with or a RegExp to test against the field
20275 * @param {Boolean} anyMatch True to match any part not just the beginning
20276 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20278 query : function(property, value, anyMatch){
20279 var fn = this.createFilterFn(property, value, anyMatch);
20280 return fn ? this.queryBy(fn) : this.data.clone();
20284 * Query by a function. The specified function will be called with each
20285 * record in this data source. If the function returns true the record is included
20287 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20288 * @param {Object} scope (optional) The scope of the function (defaults to this)
20289 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20291 queryBy : function(fn, scope){
20292 var data = this.snapshot || this.data;
20293 return data.filterBy(fn, scope||this);
20297 * Collects unique values for a particular dataIndex from this store.
20298 * @param {String} dataIndex The property to collect
20299 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
20300 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
20301 * @return {Array} An array of the unique values
20303 collect : function(dataIndex, allowNull, bypassFilter){
20304 var d = (bypassFilter === true && this.snapshot) ?
20305 this.snapshot.items : this.data.items;
20306 var v, sv, r = [], l = {};
20307 for(var i = 0, len = d.length; i < len; i++){
20308 v = d[i].data[dataIndex];
20310 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
20319 * Revert to a view of the Record cache with no filtering applied.
20320 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
20322 clearFilter : function(suppressEvent){
20323 if(this.snapshot && this.snapshot != this.data){
20324 this.data = this.snapshot;
20325 delete this.snapshot;
20326 if(suppressEvent !== true){
20327 this.fireEvent("datachanged", this);
20333 afterEdit : function(record){
20334 if(this.modified.indexOf(record) == -1){
20335 this.modified.push(record);
20337 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
20341 afterReject : function(record){
20342 this.modified.remove(record);
20343 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
20347 afterCommit : function(record){
20348 this.modified.remove(record);
20349 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
20353 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
20354 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
20356 commitChanges : function(){
20357 var m = this.modified.slice(0);
20358 this.modified = [];
20359 for(var i = 0, len = m.length; i < len; i++){
20365 * Cancel outstanding changes on all changed records.
20367 rejectChanges : function(){
20368 var m = this.modified.slice(0);
20369 this.modified = [];
20370 for(var i = 0, len = m.length; i < len; i++){
20375 onMetaChange : function(meta, rtype, o){
20376 this.recordType = rtype;
20377 this.fields = rtype.prototype.fields;
20378 delete this.snapshot;
20379 this.sortInfo = meta.sortInfo || this.sortInfo;
20380 this.modified = [];
20381 this.fireEvent('metachange', this, this.reader.meta);
20385 * Ext JS Library 1.1.1
20386 * Copyright(c) 2006-2007, Ext JS, LLC.
20388 * Originally Released Under LGPL - original licence link has changed is not relivant.
20391 * <script type="text/javascript">
20395 * @class Roo.data.SimpleStore
20396 * @extends Roo.data.Store
20397 * Small helper class to make creating Stores from Array data easier.
20398 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
20399 * @cfg {Array} fields An array of field definition objects, or field name strings.
20400 * @cfg {Array} data The multi-dimensional array of data
20402 * @param {Object} config
20404 Roo.data.SimpleStore = function(config){
20405 Roo.data.SimpleStore.superclass.constructor.call(this, {
20407 reader: new Roo.data.ArrayReader({
20410 Roo.data.Record.create(config.fields)
20412 proxy : new Roo.data.MemoryProxy(config.data)
20416 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
20418 * Ext JS Library 1.1.1
20419 * Copyright(c) 2006-2007, Ext JS, LLC.
20421 * Originally Released Under LGPL - original licence link has changed is not relivant.
20424 * <script type="text/javascript">
20429 * @extends Roo.data.Store
20430 * @class Roo.data.JsonStore
20431 * Small helper class to make creating Stores for JSON data easier. <br/>
20433 var store = new Roo.data.JsonStore({
20434 url: 'get-images.php',
20436 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
20439 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
20440 * JsonReader and HttpProxy (unless inline data is provided).</b>
20441 * @cfg {Array} fields An array of field definition objects, or field name strings.
20443 * @param {Object} config
20445 Roo.data.JsonStore = function(c){
20446 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
20447 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
20448 reader: new Roo.data.JsonReader(c, c.fields)
20451 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
20453 * Ext JS Library 1.1.1
20454 * Copyright(c) 2006-2007, Ext JS, LLC.
20456 * Originally Released Under LGPL - original licence link has changed is not relivant.
20459 * <script type="text/javascript">
20463 Roo.data.Field = function(config){
20464 if(typeof config == "string"){
20465 config = {name: config};
20467 Roo.apply(this, config);
20470 this.type = "auto";
20473 var st = Roo.data.SortTypes;
20474 // named sortTypes are supported, here we look them up
20475 if(typeof this.sortType == "string"){
20476 this.sortType = st[this.sortType];
20479 // set default sortType for strings and dates
20480 if(!this.sortType){
20483 this.sortType = st.asUCString;
20486 this.sortType = st.asDate;
20489 this.sortType = st.none;
20494 var stripRe = /[\$,%]/g;
20496 // prebuilt conversion function for this field, instead of
20497 // switching every time we're reading a value
20499 var cv, dateFormat = this.dateFormat;
20504 cv = function(v){ return v; };
20507 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20511 return v !== undefined && v !== null && v !== '' ?
20512 parseInt(String(v).replace(stripRe, ""), 10) : '';
20517 return v !== undefined && v !== null && v !== '' ?
20518 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20523 cv = function(v){ return v === true || v === "true" || v == 1; };
20530 if(v instanceof Date){
20534 if(dateFormat == "timestamp"){
20535 return new Date(v*1000);
20537 return Date.parseDate(v, dateFormat);
20539 var parsed = Date.parse(v);
20540 return parsed ? new Date(parsed) : null;
20549 Roo.data.Field.prototype = {
20557 * Ext JS Library 1.1.1
20558 * Copyright(c) 2006-2007, Ext JS, LLC.
20560 * Originally Released Under LGPL - original licence link has changed is not relivant.
20563 * <script type="text/javascript">
20566 // Base class for reading structured data from a data source. This class is intended to be
20567 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20570 * @class Roo.data.DataReader
20571 * Base class for reading structured data from a data source. This class is intended to be
20572 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20575 Roo.data.DataReader = function(meta, recordType){
20579 this.recordType = recordType instanceof Array ?
20580 Roo.data.Record.create(recordType) : recordType;
20583 Roo.data.DataReader.prototype = {
20585 * Create an empty record
20586 * @param {Object} data (optional) - overlay some values
20587 * @return {Roo.data.Record} record created.
20589 newRow : function(d) {
20591 this.recordType.prototype.fields.each(function(c) {
20593 case 'int' : da[c.name] = 0; break;
20594 case 'date' : da[c.name] = new Date(); break;
20595 case 'float' : da[c.name] = 0.0; break;
20596 case 'boolean' : da[c.name] = false; break;
20597 default : da[c.name] = ""; break;
20601 return new this.recordType(Roo.apply(da, d));
20606 * Ext JS Library 1.1.1
20607 * Copyright(c) 2006-2007, Ext JS, LLC.
20609 * Originally Released Under LGPL - original licence link has changed is not relivant.
20612 * <script type="text/javascript">
20616 * @class Roo.data.DataProxy
20617 * @extends Roo.data.Observable
20618 * This class is an abstract base class for implementations which provide retrieval of
20619 * unformatted data objects.<br>
20621 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20622 * (of the appropriate type which knows how to parse the data object) to provide a block of
20623 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20625 * Custom implementations must implement the load method as described in
20626 * {@link Roo.data.HttpProxy#load}.
20628 Roo.data.DataProxy = function(){
20631 * @event beforeload
20632 * Fires before a network request is made to retrieve a data object.
20633 * @param {Object} This DataProxy object.
20634 * @param {Object} params The params parameter to the load function.
20639 * Fires before the load method's callback is called.
20640 * @param {Object} This DataProxy object.
20641 * @param {Object} o The data object.
20642 * @param {Object} arg The callback argument object passed to the load function.
20646 * @event loadexception
20647 * Fires if an Exception occurs during data retrieval.
20648 * @param {Object} This DataProxy object.
20649 * @param {Object} o The data object.
20650 * @param {Object} arg The callback argument object passed to the load function.
20651 * @param {Object} e The Exception.
20653 loadexception : true
20655 Roo.data.DataProxy.superclass.constructor.call(this);
20658 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20661 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20665 * Ext JS Library 1.1.1
20666 * Copyright(c) 2006-2007, Ext JS, LLC.
20668 * Originally Released Under LGPL - original licence link has changed is not relivant.
20671 * <script type="text/javascript">
20674 * @class Roo.data.MemoryProxy
20675 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20676 * to the Reader when its load method is called.
20678 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20680 Roo.data.MemoryProxy = function(data){
20684 Roo.data.MemoryProxy.superclass.constructor.call(this);
20688 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20690 * Load data from the requested source (in this case an in-memory
20691 * data object passed to the constructor), read the data object into
20692 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20693 * process that block using the passed callback.
20694 * @param {Object} params This parameter is not used by the MemoryProxy class.
20695 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20696 * object into a block of Roo.data.Records.
20697 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20698 * The function must be passed <ul>
20699 * <li>The Record block object</li>
20700 * <li>The "arg" argument from the load function</li>
20701 * <li>A boolean success indicator</li>
20703 * @param {Object} scope The scope in which to call the callback
20704 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20706 load : function(params, reader, callback, scope, arg){
20707 params = params || {};
20710 result = reader.readRecords(this.data);
20712 this.fireEvent("loadexception", this, arg, null, e);
20713 callback.call(scope, null, arg, false);
20716 callback.call(scope, result, arg, true);
20720 update : function(params, records){
20725 * Ext JS Library 1.1.1
20726 * Copyright(c) 2006-2007, Ext JS, LLC.
20728 * Originally Released Under LGPL - original licence link has changed is not relivant.
20731 * <script type="text/javascript">
20734 * @class Roo.data.HttpProxy
20735 * @extends Roo.data.DataProxy
20736 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20737 * configured to reference a certain URL.<br><br>
20739 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20740 * from which the running page was served.<br><br>
20742 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20744 * Be aware that to enable the browser to parse an XML document, the server must set
20745 * the Content-Type header in the HTTP response to "text/xml".
20747 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20748 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20749 * will be used to make the request.
20751 Roo.data.HttpProxy = function(conn){
20752 Roo.data.HttpProxy.superclass.constructor.call(this);
20753 // is conn a conn config or a real conn?
20755 this.useAjax = !conn || !conn.events;
20759 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20760 // thse are take from connection...
20763 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20766 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20767 * extra parameters to each request made by this object. (defaults to undefined)
20770 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20771 * to each request made by this object. (defaults to undefined)
20774 * @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)
20777 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20780 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20786 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20790 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20791 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20792 * a finer-grained basis than the DataProxy events.
20794 getConnection : function(){
20795 return this.useAjax ? Roo.Ajax : this.conn;
20799 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20800 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20801 * process that block using the passed callback.
20802 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20803 * for the request to the remote server.
20804 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20805 * object into a block of Roo.data.Records.
20806 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20807 * The function must be passed <ul>
20808 * <li>The Record block object</li>
20809 * <li>The "arg" argument from the load function</li>
20810 * <li>A boolean success indicator</li>
20812 * @param {Object} scope The scope in which to call the callback
20813 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20815 load : function(params, reader, callback, scope, arg){
20816 if(this.fireEvent("beforeload", this, params) !== false){
20818 params : params || {},
20820 callback : callback,
20825 callback : this.loadResponse,
20829 Roo.applyIf(o, this.conn);
20830 if(this.activeRequest){
20831 Roo.Ajax.abort(this.activeRequest);
20833 this.activeRequest = Roo.Ajax.request(o);
20835 this.conn.request(o);
20838 callback.call(scope||this, null, arg, false);
20843 loadResponse : function(o, success, response){
20844 delete this.activeRequest;
20846 this.fireEvent("loadexception", this, o, response);
20847 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20852 result = o.reader.read(response);
20854 this.fireEvent("loadexception", this, o, response, e);
20855 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20859 this.fireEvent("load", this, o, o.request.arg);
20860 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20864 update : function(dataSet){
20869 updateResponse : function(dataSet){
20874 * Ext JS Library 1.1.1
20875 * Copyright(c) 2006-2007, Ext JS, LLC.
20877 * Originally Released Under LGPL - original licence link has changed is not relivant.
20880 * <script type="text/javascript">
20884 * @class Roo.data.ScriptTagProxy
20885 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20886 * other than the originating domain of the running page.<br><br>
20888 * <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
20889 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20891 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20892 * source code that is used as the source inside a <script> tag.<br><br>
20894 * In order for the browser to process the returned data, the server must wrap the data object
20895 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20896 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20897 * depending on whether the callback name was passed:
20900 boolean scriptTag = false;
20901 String cb = request.getParameter("callback");
20904 response.setContentType("text/javascript");
20906 response.setContentType("application/x-json");
20908 Writer out = response.getWriter();
20910 out.write(cb + "(");
20912 out.print(dataBlock.toJsonString());
20919 * @param {Object} config A configuration object.
20921 Roo.data.ScriptTagProxy = function(config){
20922 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20923 Roo.apply(this, config);
20924 this.head = document.getElementsByTagName("head")[0];
20927 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20929 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20931 * @cfg {String} url The URL from which to request the data object.
20934 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20938 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20939 * the server the name of the callback function set up by the load call to process the returned data object.
20940 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20941 * javascript output which calls this named function passing the data object as its only parameter.
20943 callbackParam : "callback",
20945 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20946 * name to the request.
20951 * Load data from the configured URL, read the data object into
20952 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20953 * process that block using the passed callback.
20954 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20955 * for the request to the remote server.
20956 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20957 * object into a block of Roo.data.Records.
20958 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20959 * The function must be passed <ul>
20960 * <li>The Record block object</li>
20961 * <li>The "arg" argument from the load function</li>
20962 * <li>A boolean success indicator</li>
20964 * @param {Object} scope The scope in which to call the callback
20965 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20967 load : function(params, reader, callback, scope, arg){
20968 if(this.fireEvent("beforeload", this, params) !== false){
20970 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20972 var url = this.url;
20973 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20975 url += "&_dc=" + (new Date().getTime());
20977 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20980 cb : "stcCallback"+transId,
20981 scriptId : "stcScript"+transId,
20985 callback : callback,
20991 window[trans.cb] = function(o){
20992 conn.handleResponse(o, trans);
20995 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20997 if(this.autoAbort !== false){
21001 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
21003 var script = document.createElement("script");
21004 script.setAttribute("src", url);
21005 script.setAttribute("type", "text/javascript");
21006 script.setAttribute("id", trans.scriptId);
21007 this.head.appendChild(script);
21009 this.trans = trans;
21011 callback.call(scope||this, null, arg, false);
21016 isLoading : function(){
21017 return this.trans ? true : false;
21021 * Abort the current server request.
21023 abort : function(){
21024 if(this.isLoading()){
21025 this.destroyTrans(this.trans);
21030 destroyTrans : function(trans, isLoaded){
21031 this.head.removeChild(document.getElementById(trans.scriptId));
21032 clearTimeout(trans.timeoutId);
21034 window[trans.cb] = undefined;
21036 delete window[trans.cb];
21039 // if hasn't been loaded, wait for load to remove it to prevent script error
21040 window[trans.cb] = function(){
21041 window[trans.cb] = undefined;
21043 delete window[trans.cb];
21050 handleResponse : function(o, trans){
21051 this.trans = false;
21052 this.destroyTrans(trans, true);
21055 result = trans.reader.readRecords(o);
21057 this.fireEvent("loadexception", this, o, trans.arg, e);
21058 trans.callback.call(trans.scope||window, null, trans.arg, false);
21061 this.fireEvent("load", this, o, trans.arg);
21062 trans.callback.call(trans.scope||window, result, trans.arg, true);
21066 handleFailure : function(trans){
21067 this.trans = false;
21068 this.destroyTrans(trans, false);
21069 this.fireEvent("loadexception", this, null, trans.arg);
21070 trans.callback.call(trans.scope||window, null, trans.arg, false);
21074 * Ext JS Library 1.1.1
21075 * Copyright(c) 2006-2007, Ext JS, LLC.
21077 * Originally Released Under LGPL - original licence link has changed is not relivant.
21080 * <script type="text/javascript">
21084 * @class Roo.data.JsonReader
21085 * @extends Roo.data.DataReader
21086 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
21087 * based on mappings in a provided Roo.data.Record constructor.
21089 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
21090 * in the reply previously.
21095 var RecordDef = Roo.data.Record.create([
21096 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21097 {name: 'occupation'} // This field will use "occupation" as the mapping.
21099 var myReader = new Roo.data.JsonReader({
21100 totalProperty: "results", // The property which contains the total dataset size (optional)
21101 root: "rows", // The property which contains an Array of row objects
21102 id: "id" // The property within each row object that provides an ID for the record (optional)
21106 * This would consume a JSON file like this:
21108 { 'results': 2, 'rows': [
21109 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
21110 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
21113 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
21114 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21115 * paged from the remote server.
21116 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
21117 * @cfg {String} root name of the property which contains the Array of row objects.
21118 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
21120 * Create a new JsonReader
21121 * @param {Object} meta Metadata configuration options
21122 * @param {Object} recordType Either an Array of field definition objects,
21123 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
21125 Roo.data.JsonReader = function(meta, recordType){
21128 // set some defaults:
21129 Roo.applyIf(meta, {
21130 totalProperty: 'total',
21131 successProperty : 'success',
21136 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21138 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
21141 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
21142 * Used by Store query builder to append _requestMeta to params.
21145 metaFromRemote : false,
21147 * This method is only used by a DataProxy which has retrieved data from a remote server.
21148 * @param {Object} response The XHR object which contains the JSON data in its responseText.
21149 * @return {Object} data A data block which is used by an Roo.data.Store object as
21150 * a cache of Roo.data.Records.
21152 read : function(response){
21153 var json = response.responseText;
21155 var o = /* eval:var:o */ eval("("+json+")");
21157 throw {message: "JsonReader.read: Json object not found"};
21163 this.metaFromRemote = true;
21164 this.meta = o.metaData;
21165 this.recordType = Roo.data.Record.create(o.metaData.fields);
21166 this.onMetaChange(this.meta, this.recordType, o);
21168 return this.readRecords(o);
21171 // private function a store will implement
21172 onMetaChange : function(meta, recordType, o){
21179 simpleAccess: function(obj, subsc) {
21186 getJsonAccessor: function(){
21188 return function(expr) {
21190 return(re.test(expr))
21191 ? new Function("obj", "return obj." + expr)
21196 return Roo.emptyFn;
21201 * Create a data block containing Roo.data.Records from an XML document.
21202 * @param {Object} o An object which contains an Array of row objects in the property specified
21203 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
21204 * which contains the total size of the dataset.
21205 * @return {Object} data A data block which is used by an Roo.data.Store object as
21206 * a cache of Roo.data.Records.
21208 readRecords : function(o){
21210 * After any data loads, the raw JSON data is available for further custom processing.
21214 var s = this.meta, Record = this.recordType,
21215 f = Record.prototype.fields, fi = f.items, fl = f.length;
21217 // Generate extraction functions for the totalProperty, the root, the id, and for each field
21219 if(s.totalProperty) {
21220 this.getTotal = this.getJsonAccessor(s.totalProperty);
21222 if(s.successProperty) {
21223 this.getSuccess = this.getJsonAccessor(s.successProperty);
21225 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
21227 var g = this.getJsonAccessor(s.id);
21228 this.getId = function(rec) {
21230 return (r === undefined || r === "") ? null : r;
21233 this.getId = function(){return null;};
21236 for(var jj = 0; jj < fl; jj++){
21238 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
21239 this.ef[jj] = this.getJsonAccessor(map);
21243 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
21244 if(s.totalProperty){
21245 var vt = parseInt(this.getTotal(o), 10);
21250 if(s.successProperty){
21251 var vs = this.getSuccess(o);
21252 if(vs === false || vs === 'false'){
21257 for(var i = 0; i < c; i++){
21260 var id = this.getId(n);
21261 for(var j = 0; j < fl; j++){
21263 var v = this.ef[j](n);
21265 Roo.log('missing convert for ' + f.name);
21269 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
21271 var record = new Record(values, id);
21273 records[i] = record;
21278 totalRecords : totalRecords
21283 * Ext JS Library 1.1.1
21284 * Copyright(c) 2006-2007, Ext JS, LLC.
21286 * Originally Released Under LGPL - original licence link has changed is not relivant.
21289 * <script type="text/javascript">
21293 * @class Roo.data.XmlReader
21294 * @extends Roo.data.DataReader
21295 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
21296 * based on mappings in a provided Roo.data.Record constructor.<br><br>
21298 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
21299 * header in the HTTP response must be set to "text/xml".</em>
21303 var RecordDef = Roo.data.Record.create([
21304 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21305 {name: 'occupation'} // This field will use "occupation" as the mapping.
21307 var myReader = new Roo.data.XmlReader({
21308 totalRecords: "results", // The element which contains the total dataset size (optional)
21309 record: "row", // The repeated element which contains row information
21310 id: "id" // The element within the row that provides an ID for the record (optional)
21314 * This would consume an XML file like this:
21318 <results>2</results>
21321 <name>Bill</name>
21322 <occupation>Gardener</occupation>
21326 <name>Ben</name>
21327 <occupation>Horticulturalist</occupation>
21331 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
21332 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21333 * paged from the remote server.
21334 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
21335 * @cfg {String} success The DomQuery path to the success attribute used by forms.
21336 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
21337 * a record identifier value.
21339 * Create a new XmlReader
21340 * @param {Object} meta Metadata configuration options
21341 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
21342 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
21343 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
21345 Roo.data.XmlReader = function(meta, recordType){
21347 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21349 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
21351 * This method is only used by a DataProxy which has retrieved data from a remote server.
21352 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
21353 * to contain a method called 'responseXML' that returns an XML document object.
21354 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21355 * a cache of Roo.data.Records.
21357 read : function(response){
21358 var doc = response.responseXML;
21360 throw {message: "XmlReader.read: XML Document not available"};
21362 return this.readRecords(doc);
21366 * Create a data block containing Roo.data.Records from an XML document.
21367 * @param {Object} doc A parsed XML document.
21368 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21369 * a cache of Roo.data.Records.
21371 readRecords : function(doc){
21373 * After any data loads/reads, the raw XML Document is available for further custom processing.
21374 * @type XMLDocument
21376 this.xmlData = doc;
21377 var root = doc.documentElement || doc;
21378 var q = Roo.DomQuery;
21379 var recordType = this.recordType, fields = recordType.prototype.fields;
21380 var sid = this.meta.id;
21381 var totalRecords = 0, success = true;
21382 if(this.meta.totalRecords){
21383 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
21386 if(this.meta.success){
21387 var sv = q.selectValue(this.meta.success, root, true);
21388 success = sv !== false && sv !== 'false';
21391 var ns = q.select(this.meta.record, root);
21392 for(var i = 0, len = ns.length; i < len; i++) {
21395 var id = sid ? q.selectValue(sid, n) : undefined;
21396 for(var j = 0, jlen = fields.length; j < jlen; j++){
21397 var f = fields.items[j];
21398 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
21400 values[f.name] = v;
21402 var record = new recordType(values, id);
21404 records[records.length] = record;
21410 totalRecords : totalRecords || records.length
21415 * Ext JS Library 1.1.1
21416 * Copyright(c) 2006-2007, Ext JS, LLC.
21418 * Originally Released Under LGPL - original licence link has changed is not relivant.
21421 * <script type="text/javascript">
21425 * @class Roo.data.ArrayReader
21426 * @extends Roo.data.DataReader
21427 * Data reader class to create an Array of Roo.data.Record objects from an Array.
21428 * Each element of that Array represents a row of data fields. The
21429 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
21430 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
21434 var RecordDef = Roo.data.Record.create([
21435 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
21436 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
21438 var myReader = new Roo.data.ArrayReader({
21439 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
21443 * This would consume an Array like this:
21445 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
21447 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
21449 * Create a new JsonReader
21450 * @param {Object} meta Metadata configuration options.
21451 * @param {Object} recordType Either an Array of field definition objects
21452 * as specified to {@link Roo.data.Record#create},
21453 * or an {@link Roo.data.Record} object
21454 * created using {@link Roo.data.Record#create}.
21456 Roo.data.ArrayReader = function(meta, recordType){
21457 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
21460 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
21462 * Create a data block containing Roo.data.Records from an XML document.
21463 * @param {Object} o An Array of row objects which represents the dataset.
21464 * @return {Object} data A data block which is used by an Roo.data.Store object as
21465 * a cache of Roo.data.Records.
21467 readRecords : function(o){
21468 var sid = this.meta ? this.meta.id : null;
21469 var recordType = this.recordType, fields = recordType.prototype.fields;
21472 for(var i = 0; i < root.length; i++){
21475 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
21476 for(var j = 0, jlen = fields.length; j < jlen; j++){
21477 var f = fields.items[j];
21478 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21479 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21481 values[f.name] = v;
21483 var record = new recordType(values, id);
21485 records[records.length] = record;
21489 totalRecords : records.length
21494 * Ext JS Library 1.1.1
21495 * Copyright(c) 2006-2007, Ext JS, LLC.
21497 * Originally Released Under LGPL - original licence link has changed is not relivant.
21500 * <script type="text/javascript">
21505 * @class Roo.data.Tree
21506 * @extends Roo.util.Observable
21507 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21508 * in the tree have most standard DOM functionality.
21510 * @param {Node} root (optional) The root node
21512 Roo.data.Tree = function(root){
21513 this.nodeHash = {};
21515 * The root node for this tree
21520 this.setRootNode(root);
21525 * Fires when a new child node is appended to a node in this tree.
21526 * @param {Tree} tree The owner tree
21527 * @param {Node} parent The parent node
21528 * @param {Node} node The newly appended node
21529 * @param {Number} index The index of the newly appended node
21534 * Fires when a child node is removed from a node in this tree.
21535 * @param {Tree} tree The owner tree
21536 * @param {Node} parent The parent node
21537 * @param {Node} node The child node removed
21542 * Fires when a node is moved to a new location in the tree
21543 * @param {Tree} tree The owner tree
21544 * @param {Node} node The node moved
21545 * @param {Node} oldParent The old parent of this node
21546 * @param {Node} newParent The new parent of this node
21547 * @param {Number} index The index it was moved to
21552 * Fires when a new child node is inserted in a node in this tree.
21553 * @param {Tree} tree The owner tree
21554 * @param {Node} parent The parent node
21555 * @param {Node} node The child node inserted
21556 * @param {Node} refNode The child node the node was inserted before
21560 * @event beforeappend
21561 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21562 * @param {Tree} tree The owner tree
21563 * @param {Node} parent The parent node
21564 * @param {Node} node The child node to be appended
21566 "beforeappend" : true,
21568 * @event beforeremove
21569 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21570 * @param {Tree} tree The owner tree
21571 * @param {Node} parent The parent node
21572 * @param {Node} node The child node to be removed
21574 "beforeremove" : true,
21576 * @event beforemove
21577 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21578 * @param {Tree} tree The owner tree
21579 * @param {Node} node The node being moved
21580 * @param {Node} oldParent The parent of the node
21581 * @param {Node} newParent The new parent the node is moving to
21582 * @param {Number} index The index it is being moved to
21584 "beforemove" : true,
21586 * @event beforeinsert
21587 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21588 * @param {Tree} tree The owner tree
21589 * @param {Node} parent The parent node
21590 * @param {Node} node The child node to be inserted
21591 * @param {Node} refNode The child node the node is being inserted before
21593 "beforeinsert" : true
21596 Roo.data.Tree.superclass.constructor.call(this);
21599 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21600 pathSeparator: "/",
21602 proxyNodeEvent : function(){
21603 return this.fireEvent.apply(this, arguments);
21607 * Returns the root node for this tree.
21610 getRootNode : function(){
21615 * Sets the root node for this tree.
21616 * @param {Node} node
21619 setRootNode : function(node){
21621 node.ownerTree = this;
21622 node.isRoot = true;
21623 this.registerNode(node);
21628 * Gets a node in this tree by its id.
21629 * @param {String} id
21632 getNodeById : function(id){
21633 return this.nodeHash[id];
21636 registerNode : function(node){
21637 this.nodeHash[node.id] = node;
21640 unregisterNode : function(node){
21641 delete this.nodeHash[node.id];
21644 toString : function(){
21645 return "[Tree"+(this.id?" "+this.id:"")+"]";
21650 * @class Roo.data.Node
21651 * @extends Roo.util.Observable
21652 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21653 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21655 * @param {Object} attributes The attributes/config for the node
21657 Roo.data.Node = function(attributes){
21659 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21662 this.attributes = attributes || {};
21663 this.leaf = this.attributes.leaf;
21665 * The node id. @type String
21667 this.id = this.attributes.id;
21669 this.id = Roo.id(null, "ynode-");
21670 this.attributes.id = this.id;
21675 * All child nodes of this node. @type Array
21677 this.childNodes = [];
21678 if(!this.childNodes.indexOf){ // indexOf is a must
21679 this.childNodes.indexOf = function(o){
21680 for(var i = 0, len = this.length; i < len; i++){
21689 * The parent node for this node. @type Node
21691 this.parentNode = null;
21693 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21695 this.firstChild = null;
21697 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21699 this.lastChild = null;
21701 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21703 this.previousSibling = null;
21705 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21707 this.nextSibling = null;
21712 * Fires when a new child node is appended
21713 * @param {Tree} tree The owner tree
21714 * @param {Node} this This node
21715 * @param {Node} node The newly appended node
21716 * @param {Number} index The index of the newly appended node
21721 * Fires when a child node is removed
21722 * @param {Tree} tree The owner tree
21723 * @param {Node} this This node
21724 * @param {Node} node The removed node
21729 * Fires when this node is moved to a new location in the tree
21730 * @param {Tree} tree The owner tree
21731 * @param {Node} this This node
21732 * @param {Node} oldParent The old parent of this node
21733 * @param {Node} newParent The new parent of this node
21734 * @param {Number} index The index it was moved to
21739 * Fires when a new child node is inserted.
21740 * @param {Tree} tree The owner tree
21741 * @param {Node} this This node
21742 * @param {Node} node The child node inserted
21743 * @param {Node} refNode The child node the node was inserted before
21747 * @event beforeappend
21748 * Fires before a new child is appended, return false to cancel the append.
21749 * @param {Tree} tree The owner tree
21750 * @param {Node} this This node
21751 * @param {Node} node The child node to be appended
21753 "beforeappend" : true,
21755 * @event beforeremove
21756 * Fires before a child is removed, return false to cancel the remove.
21757 * @param {Tree} tree The owner tree
21758 * @param {Node} this This node
21759 * @param {Node} node The child node to be removed
21761 "beforeremove" : true,
21763 * @event beforemove
21764 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21765 * @param {Tree} tree The owner tree
21766 * @param {Node} this This node
21767 * @param {Node} oldParent The parent of this node
21768 * @param {Node} newParent The new parent this node is moving to
21769 * @param {Number} index The index it is being moved to
21771 "beforemove" : true,
21773 * @event beforeinsert
21774 * Fires before a new child is inserted, return false to cancel the insert.
21775 * @param {Tree} tree The owner tree
21776 * @param {Node} this This node
21777 * @param {Node} node The child node to be inserted
21778 * @param {Node} refNode The child node the node is being inserted before
21780 "beforeinsert" : true
21782 this.listeners = this.attributes.listeners;
21783 Roo.data.Node.superclass.constructor.call(this);
21786 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21787 fireEvent : function(evtName){
21788 // first do standard event for this node
21789 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21792 // then bubble it up to the tree if the event wasn't cancelled
21793 var ot = this.getOwnerTree();
21795 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21803 * Returns true if this node is a leaf
21804 * @return {Boolean}
21806 isLeaf : function(){
21807 return this.leaf === true;
21811 setFirstChild : function(node){
21812 this.firstChild = node;
21816 setLastChild : function(node){
21817 this.lastChild = node;
21822 * Returns true if this node is the last child of its parent
21823 * @return {Boolean}
21825 isLast : function(){
21826 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21830 * Returns true if this node is the first child of its parent
21831 * @return {Boolean}
21833 isFirst : function(){
21834 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21837 hasChildNodes : function(){
21838 return !this.isLeaf() && this.childNodes.length > 0;
21842 * Insert node(s) as the last child node of this node.
21843 * @param {Node/Array} node The node or Array of nodes to append
21844 * @return {Node} The appended node if single append, or null if an array was passed
21846 appendChild : function(node){
21848 if(node instanceof Array){
21850 }else if(arguments.length > 1){
21853 // if passed an array or multiple args do them one by one
21855 for(var i = 0, len = multi.length; i < len; i++) {
21856 this.appendChild(multi[i]);
21859 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21862 var index = this.childNodes.length;
21863 var oldParent = node.parentNode;
21864 // it's a move, make sure we move it cleanly
21866 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21869 oldParent.removeChild(node);
21871 index = this.childNodes.length;
21873 this.setFirstChild(node);
21875 this.childNodes.push(node);
21876 node.parentNode = this;
21877 var ps = this.childNodes[index-1];
21879 node.previousSibling = ps;
21880 ps.nextSibling = node;
21882 node.previousSibling = null;
21884 node.nextSibling = null;
21885 this.setLastChild(node);
21886 node.setOwnerTree(this.getOwnerTree());
21887 this.fireEvent("append", this.ownerTree, this, node, index);
21889 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21896 * Removes a child node from this node.
21897 * @param {Node} node The node to remove
21898 * @return {Node} The removed node
21900 removeChild : function(node){
21901 var index = this.childNodes.indexOf(node);
21905 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21909 // remove it from childNodes collection
21910 this.childNodes.splice(index, 1);
21913 if(node.previousSibling){
21914 node.previousSibling.nextSibling = node.nextSibling;
21916 if(node.nextSibling){
21917 node.nextSibling.previousSibling = node.previousSibling;
21920 // update child refs
21921 if(this.firstChild == node){
21922 this.setFirstChild(node.nextSibling);
21924 if(this.lastChild == node){
21925 this.setLastChild(node.previousSibling);
21928 node.setOwnerTree(null);
21929 // clear any references from the node
21930 node.parentNode = null;
21931 node.previousSibling = null;
21932 node.nextSibling = null;
21933 this.fireEvent("remove", this.ownerTree, this, node);
21938 * Inserts the first node before the second node in this nodes childNodes collection.
21939 * @param {Node} node The node to insert
21940 * @param {Node} refNode The node to insert before (if null the node is appended)
21941 * @return {Node} The inserted node
21943 insertBefore : function(node, refNode){
21944 if(!refNode){ // like standard Dom, refNode can be null for append
21945 return this.appendChild(node);
21948 if(node == refNode){
21952 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21955 var index = this.childNodes.indexOf(refNode);
21956 var oldParent = node.parentNode;
21957 var refIndex = index;
21959 // when moving internally, indexes will change after remove
21960 if(oldParent == this && this.childNodes.indexOf(node) < index){
21964 // it's a move, make sure we move it cleanly
21966 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21969 oldParent.removeChild(node);
21972 this.setFirstChild(node);
21974 this.childNodes.splice(refIndex, 0, node);
21975 node.parentNode = this;
21976 var ps = this.childNodes[refIndex-1];
21978 node.previousSibling = ps;
21979 ps.nextSibling = node;
21981 node.previousSibling = null;
21983 node.nextSibling = refNode;
21984 refNode.previousSibling = node;
21985 node.setOwnerTree(this.getOwnerTree());
21986 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21988 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21994 * Returns the child node at the specified index.
21995 * @param {Number} index
21998 item : function(index){
21999 return this.childNodes[index];
22003 * Replaces one child node in this node with another.
22004 * @param {Node} newChild The replacement node
22005 * @param {Node} oldChild The node to replace
22006 * @return {Node} The replaced node
22008 replaceChild : function(newChild, oldChild){
22009 this.insertBefore(newChild, oldChild);
22010 this.removeChild(oldChild);
22015 * Returns the index of a child node
22016 * @param {Node} node
22017 * @return {Number} The index of the node or -1 if it was not found
22019 indexOf : function(child){
22020 return this.childNodes.indexOf(child);
22024 * Returns the tree this node is in.
22027 getOwnerTree : function(){
22028 // if it doesn't have one, look for one
22029 if(!this.ownerTree){
22033 this.ownerTree = p.ownerTree;
22039 return this.ownerTree;
22043 * Returns depth of this node (the root node has a depth of 0)
22046 getDepth : function(){
22049 while(p.parentNode){
22057 setOwnerTree : function(tree){
22058 // if it's move, we need to update everyone
22059 if(tree != this.ownerTree){
22060 if(this.ownerTree){
22061 this.ownerTree.unregisterNode(this);
22063 this.ownerTree = tree;
22064 var cs = this.childNodes;
22065 for(var i = 0, len = cs.length; i < len; i++) {
22066 cs[i].setOwnerTree(tree);
22069 tree.registerNode(this);
22075 * Returns the path for this node. The path can be used to expand or select this node programmatically.
22076 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
22077 * @return {String} The path
22079 getPath : function(attr){
22080 attr = attr || "id";
22081 var p = this.parentNode;
22082 var b = [this.attributes[attr]];
22084 b.unshift(p.attributes[attr]);
22087 var sep = this.getOwnerTree().pathSeparator;
22088 return sep + b.join(sep);
22092 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22093 * function call will be the scope provided or the current node. The arguments to the function
22094 * will be the args provided or the current node. If the function returns false at any point,
22095 * the bubble is stopped.
22096 * @param {Function} fn The function to call
22097 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22098 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22100 bubble : function(fn, scope, args){
22103 if(fn.call(scope || p, args || p) === false){
22111 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22112 * function call will be the scope provided or the current node. The arguments to the function
22113 * will be the args provided or the current node. If the function returns false at any point,
22114 * the cascade is stopped on that branch.
22115 * @param {Function} fn The function to call
22116 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22117 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22119 cascade : function(fn, scope, args){
22120 if(fn.call(scope || this, args || this) !== false){
22121 var cs = this.childNodes;
22122 for(var i = 0, len = cs.length; i < len; i++) {
22123 cs[i].cascade(fn, scope, args);
22129 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
22130 * function call will be the scope provided or the current node. The arguments to the function
22131 * will be the args provided or the current node. If the function returns false at any point,
22132 * the iteration stops.
22133 * @param {Function} fn The function to call
22134 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22135 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22137 eachChild : function(fn, scope, args){
22138 var cs = this.childNodes;
22139 for(var i = 0, len = cs.length; i < len; i++) {
22140 if(fn.call(scope || this, args || cs[i]) === false){
22147 * Finds the first child that has the attribute with the specified value.
22148 * @param {String} attribute The attribute name
22149 * @param {Mixed} value The value to search for
22150 * @return {Node} The found child or null if none was found
22152 findChild : function(attribute, value){
22153 var cs = this.childNodes;
22154 for(var i = 0, len = cs.length; i < len; i++) {
22155 if(cs[i].attributes[attribute] == value){
22163 * Finds the first child by a custom function. The child matches if the function passed
22165 * @param {Function} fn
22166 * @param {Object} scope (optional)
22167 * @return {Node} The found child or null if none was found
22169 findChildBy : function(fn, scope){
22170 var cs = this.childNodes;
22171 for(var i = 0, len = cs.length; i < len; i++) {
22172 if(fn.call(scope||cs[i], cs[i]) === true){
22180 * Sorts this nodes children using the supplied sort function
22181 * @param {Function} fn
22182 * @param {Object} scope (optional)
22184 sort : function(fn, scope){
22185 var cs = this.childNodes;
22186 var len = cs.length;
22188 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
22190 for(var i = 0; i < len; i++){
22192 n.previousSibling = cs[i-1];
22193 n.nextSibling = cs[i+1];
22195 this.setFirstChild(n);
22198 this.setLastChild(n);
22205 * Returns true if this node is an ancestor (at any point) of the passed node.
22206 * @param {Node} node
22207 * @return {Boolean}
22209 contains : function(node){
22210 return node.isAncestor(this);
22214 * Returns true if the passed node is an ancestor (at any point) of this node.
22215 * @param {Node} node
22216 * @return {Boolean}
22218 isAncestor : function(node){
22219 var p = this.parentNode;
22229 toString : function(){
22230 return "[Node"+(this.id?" "+this.id:"")+"]";
22234 * Ext JS Library 1.1.1
22235 * Copyright(c) 2006-2007, Ext JS, LLC.
22237 * Originally Released Under LGPL - original licence link has changed is not relivant.
22240 * <script type="text/javascript">
22245 * @class Roo.ComponentMgr
22246 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
22249 Roo.ComponentMgr = function(){
22250 var all = new Roo.util.MixedCollection();
22254 * Registers a component.
22255 * @param {Roo.Component} c The component
22257 register : function(c){
22262 * Unregisters a component.
22263 * @param {Roo.Component} c The component
22265 unregister : function(c){
22270 * Returns a component by id
22271 * @param {String} id The component id
22273 get : function(id){
22274 return all.get(id);
22278 * Registers a function that will be called when a specified component is added to ComponentMgr
22279 * @param {String} id The component id
22280 * @param {Funtction} fn The callback function
22281 * @param {Object} scope The scope of the callback
22283 onAvailable : function(id, fn, scope){
22284 all.on("add", function(index, o){
22286 fn.call(scope || o, o);
22287 all.un("add", fn, scope);
22294 * Ext JS Library 1.1.1
22295 * Copyright(c) 2006-2007, Ext JS, LLC.
22297 * Originally Released Under LGPL - original licence link has changed is not relivant.
22300 * <script type="text/javascript">
22304 * @class Roo.Component
22305 * @extends Roo.util.Observable
22306 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
22307 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
22308 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
22309 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
22310 * All visual components (widgets) that require rendering into a layout should subclass Component.
22312 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
22313 * 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
22314 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
22316 Roo.Component = function(config){
22317 config = config || {};
22318 if(config.tagName || config.dom || typeof config == "string"){ // element object
22319 config = {el: config, id: config.id || config};
22321 this.initialConfig = config;
22323 Roo.apply(this, config);
22327 * Fires after the component is disabled.
22328 * @param {Roo.Component} this
22333 * Fires after the component is enabled.
22334 * @param {Roo.Component} this
22338 * @event beforeshow
22339 * Fires before the component is shown. Return false to stop the show.
22340 * @param {Roo.Component} this
22345 * Fires after the component is shown.
22346 * @param {Roo.Component} this
22350 * @event beforehide
22351 * Fires before the component is hidden. Return false to stop the hide.
22352 * @param {Roo.Component} this
22357 * Fires after the component is hidden.
22358 * @param {Roo.Component} this
22362 * @event beforerender
22363 * Fires before the component is rendered. Return false to stop the render.
22364 * @param {Roo.Component} this
22366 beforerender : true,
22369 * Fires after the component is rendered.
22370 * @param {Roo.Component} this
22374 * @event beforedestroy
22375 * Fires before the component is destroyed. Return false to stop the destroy.
22376 * @param {Roo.Component} this
22378 beforedestroy : true,
22381 * Fires after the component is destroyed.
22382 * @param {Roo.Component} this
22387 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
22389 Roo.ComponentMgr.register(this);
22390 Roo.Component.superclass.constructor.call(this);
22391 this.initComponent();
22392 if(this.renderTo){ // not supported by all components yet. use at your own risk!
22393 this.render(this.renderTo);
22394 delete this.renderTo;
22399 Roo.Component.AUTO_ID = 1000;
22401 Roo.extend(Roo.Component, Roo.util.Observable, {
22403 * @scope Roo.Component.prototype
22405 * true if this component is hidden. Read-only.
22410 * true if this component is disabled. Read-only.
22415 * true if this component has been rendered. Read-only.
22419 /** @cfg {String} disableClass
22420 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
22422 disabledClass : "x-item-disabled",
22423 /** @cfg {Boolean} allowDomMove
22424 * Whether the component can move the Dom node when rendering (defaults to true).
22426 allowDomMove : true,
22427 /** @cfg {String} hideMode
22428 * How this component should hidden. Supported values are
22429 * "visibility" (css visibility), "offsets" (negative offset position) and
22430 * "display" (css display) - defaults to "display".
22432 hideMode: 'display',
22435 ctype : "Roo.Component",
22438 * @cfg {String} actionMode
22439 * which property holds the element that used for hide() / show() / disable() / enable()
22445 getActionEl : function(){
22446 return this[this.actionMode];
22449 initComponent : Roo.emptyFn,
22451 * If this is a lazy rendering component, render it to its container element.
22452 * @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.
22454 render : function(container, position){
22455 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
22456 if(!container && this.el){
22457 this.el = Roo.get(this.el);
22458 container = this.el.dom.parentNode;
22459 this.allowDomMove = false;
22461 this.container = Roo.get(container);
22462 this.rendered = true;
22463 if(position !== undefined){
22464 if(typeof position == 'number'){
22465 position = this.container.dom.childNodes[position];
22467 position = Roo.getDom(position);
22470 this.onRender(this.container, position || null);
22472 this.el.addClass(this.cls);
22476 this.el.applyStyles(this.style);
22479 this.fireEvent("render", this);
22480 this.afterRender(this.container);
22492 // default function is not really useful
22493 onRender : function(ct, position){
22495 this.el = Roo.get(this.el);
22496 if(this.allowDomMove !== false){
22497 ct.dom.insertBefore(this.el.dom, position);
22503 getAutoCreate : function(){
22504 var cfg = typeof this.autoCreate == "object" ?
22505 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22506 if(this.id && !cfg.id){
22513 afterRender : Roo.emptyFn,
22516 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22517 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22519 destroy : function(){
22520 if(this.fireEvent("beforedestroy", this) !== false){
22521 this.purgeListeners();
22522 this.beforeDestroy();
22524 this.el.removeAllListeners();
22526 if(this.actionMode == "container"){
22527 this.container.remove();
22531 Roo.ComponentMgr.unregister(this);
22532 this.fireEvent("destroy", this);
22537 beforeDestroy : function(){
22542 onDestroy : function(){
22547 * Returns the underlying {@link Roo.Element}.
22548 * @return {Roo.Element} The element
22550 getEl : function(){
22555 * Returns the id of this component.
22558 getId : function(){
22563 * Try to focus this component.
22564 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22565 * @return {Roo.Component} this
22567 focus : function(selectText){
22570 if(selectText === true){
22571 this.el.dom.select();
22586 * Disable this component.
22587 * @return {Roo.Component} this
22589 disable : function(){
22593 this.disabled = true;
22594 this.fireEvent("disable", this);
22599 onDisable : function(){
22600 this.getActionEl().addClass(this.disabledClass);
22601 this.el.dom.disabled = true;
22605 * Enable this component.
22606 * @return {Roo.Component} this
22608 enable : function(){
22612 this.disabled = false;
22613 this.fireEvent("enable", this);
22618 onEnable : function(){
22619 this.getActionEl().removeClass(this.disabledClass);
22620 this.el.dom.disabled = false;
22624 * Convenience function for setting disabled/enabled by boolean.
22625 * @param {Boolean} disabled
22627 setDisabled : function(disabled){
22628 this[disabled ? "disable" : "enable"]();
22632 * Show this component.
22633 * @return {Roo.Component} this
22636 if(this.fireEvent("beforeshow", this) !== false){
22637 this.hidden = false;
22641 this.fireEvent("show", this);
22647 onShow : function(){
22648 var ae = this.getActionEl();
22649 if(this.hideMode == 'visibility'){
22650 ae.dom.style.visibility = "visible";
22651 }else if(this.hideMode == 'offsets'){
22652 ae.removeClass('x-hidden');
22654 ae.dom.style.display = "";
22659 * Hide this component.
22660 * @return {Roo.Component} this
22663 if(this.fireEvent("beforehide", this) !== false){
22664 this.hidden = true;
22668 this.fireEvent("hide", this);
22674 onHide : function(){
22675 var ae = this.getActionEl();
22676 if(this.hideMode == 'visibility'){
22677 ae.dom.style.visibility = "hidden";
22678 }else if(this.hideMode == 'offsets'){
22679 ae.addClass('x-hidden');
22681 ae.dom.style.display = "none";
22686 * Convenience function to hide or show this component by boolean.
22687 * @param {Boolean} visible True to show, false to hide
22688 * @return {Roo.Component} this
22690 setVisible: function(visible){
22700 * Returns true if this component is visible.
22702 isVisible : function(){
22703 return this.getActionEl().isVisible();
22706 cloneConfig : function(overrides){
22707 overrides = overrides || {};
22708 var id = overrides.id || Roo.id();
22709 var cfg = Roo.applyIf(overrides, this.initialConfig);
22710 cfg.id = id; // prevent dup id
22711 return new this.constructor(cfg);
22715 * Ext JS Library 1.1.1
22716 * Copyright(c) 2006-2007, Ext JS, LLC.
22718 * Originally Released Under LGPL - original licence link has changed is not relivant.
22721 * <script type="text/javascript">
22726 * @extends Roo.Element
22727 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22728 * automatic maintaining of shadow/shim positions.
22729 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22730 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22731 * you can pass a string with a CSS class name. False turns off the shadow.
22732 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22733 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22734 * @cfg {String} cls CSS class to add to the element
22735 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22736 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22738 * @param {Object} config An object with config options.
22739 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22742 Roo.Layer = function(config, existingEl){
22743 config = config || {};
22744 var dh = Roo.DomHelper;
22745 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22747 this.dom = Roo.getDom(existingEl);
22750 var o = config.dh || {tag: "div", cls: "x-layer"};
22751 this.dom = dh.append(pel, o);
22754 this.addClass(config.cls);
22756 this.constrain = config.constrain !== false;
22757 this.visibilityMode = Roo.Element.VISIBILITY;
22759 this.id = this.dom.id = config.id;
22761 this.id = Roo.id(this.dom);
22763 this.zindex = config.zindex || this.getZIndex();
22764 this.position("absolute", this.zindex);
22766 this.shadowOffset = config.shadowOffset || 4;
22767 this.shadow = new Roo.Shadow({
22768 offset : this.shadowOffset,
22769 mode : config.shadow
22772 this.shadowOffset = 0;
22774 this.useShim = config.shim !== false && Roo.useShims;
22775 this.useDisplay = config.useDisplay;
22779 var supr = Roo.Element.prototype;
22781 // shims are shared among layer to keep from having 100 iframes
22784 Roo.extend(Roo.Layer, Roo.Element, {
22786 getZIndex : function(){
22787 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22790 getShim : function(){
22797 var shim = shims.shift();
22799 shim = this.createShim();
22800 shim.enableDisplayMode('block');
22801 shim.dom.style.display = 'none';
22802 shim.dom.style.visibility = 'visible';
22804 var pn = this.dom.parentNode;
22805 if(shim.dom.parentNode != pn){
22806 pn.insertBefore(shim.dom, this.dom);
22808 shim.setStyle('z-index', this.getZIndex()-2);
22813 hideShim : function(){
22815 this.shim.setDisplayed(false);
22816 shims.push(this.shim);
22821 disableShadow : function(){
22823 this.shadowDisabled = true;
22824 this.shadow.hide();
22825 this.lastShadowOffset = this.shadowOffset;
22826 this.shadowOffset = 0;
22830 enableShadow : function(show){
22832 this.shadowDisabled = false;
22833 this.shadowOffset = this.lastShadowOffset;
22834 delete this.lastShadowOffset;
22842 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22843 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22844 sync : function(doShow){
22845 var sw = this.shadow;
22846 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22847 var sh = this.getShim();
22849 var w = this.getWidth(),
22850 h = this.getHeight();
22852 var l = this.getLeft(true),
22853 t = this.getTop(true);
22855 if(sw && !this.shadowDisabled){
22856 if(doShow && !sw.isVisible()){
22859 sw.realign(l, t, w, h);
22865 // fit the shim behind the shadow, so it is shimmed too
22866 var a = sw.adjusts, s = sh.dom.style;
22867 s.left = (Math.min(l, l+a.l))+"px";
22868 s.top = (Math.min(t, t+a.t))+"px";
22869 s.width = (w+a.w)+"px";
22870 s.height = (h+a.h)+"px";
22877 sh.setLeftTop(l, t);
22884 destroy : function(){
22887 this.shadow.hide();
22889 this.removeAllListeners();
22890 var pn = this.dom.parentNode;
22892 pn.removeChild(this.dom);
22894 Roo.Element.uncache(this.id);
22897 remove : function(){
22902 beginUpdate : function(){
22903 this.updating = true;
22907 endUpdate : function(){
22908 this.updating = false;
22913 hideUnders : function(negOffset){
22915 this.shadow.hide();
22921 constrainXY : function(){
22922 if(this.constrain){
22923 var vw = Roo.lib.Dom.getViewWidth(),
22924 vh = Roo.lib.Dom.getViewHeight();
22925 var s = Roo.get(document).getScroll();
22927 var xy = this.getXY();
22928 var x = xy[0], y = xy[1];
22929 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22930 // only move it if it needs it
22932 // first validate right/bottom
22933 if((x + w) > vw+s.left){
22934 x = vw - w - this.shadowOffset;
22937 if((y + h) > vh+s.top){
22938 y = vh - h - this.shadowOffset;
22941 // then make sure top/left isn't negative
22952 var ay = this.avoidY;
22953 if(y <= ay && (y+h) >= ay){
22959 supr.setXY.call(this, xy);
22965 isVisible : function(){
22966 return this.visible;
22970 showAction : function(){
22971 this.visible = true; // track visibility to prevent getStyle calls
22972 if(this.useDisplay === true){
22973 this.setDisplayed("");
22974 }else if(this.lastXY){
22975 supr.setXY.call(this, this.lastXY);
22976 }else if(this.lastLT){
22977 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22982 hideAction : function(){
22983 this.visible = false;
22984 if(this.useDisplay === true){
22985 this.setDisplayed(false);
22987 this.setLeftTop(-10000,-10000);
22991 // overridden Element method
22992 setVisible : function(v, a, d, c, e){
22997 var cb = function(){
23002 }.createDelegate(this);
23003 supr.setVisible.call(this, true, true, d, cb, e);
23006 this.hideUnders(true);
23015 }.createDelegate(this);
23017 supr.setVisible.call(this, v, a, d, cb, e);
23026 storeXY : function(xy){
23027 delete this.lastLT;
23031 storeLeftTop : function(left, top){
23032 delete this.lastXY;
23033 this.lastLT = [left, top];
23037 beforeFx : function(){
23038 this.beforeAction();
23039 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23043 afterFx : function(){
23044 Roo.Layer.superclass.afterFx.apply(this, arguments);
23045 this.sync(this.isVisible());
23049 beforeAction : function(){
23050 if(!this.updating && this.shadow){
23051 this.shadow.hide();
23055 // overridden Element method
23056 setLeft : function(left){
23057 this.storeLeftTop(left, this.getTop(true));
23058 supr.setLeft.apply(this, arguments);
23062 setTop : function(top){
23063 this.storeLeftTop(this.getLeft(true), top);
23064 supr.setTop.apply(this, arguments);
23068 setLeftTop : function(left, top){
23069 this.storeLeftTop(left, top);
23070 supr.setLeftTop.apply(this, arguments);
23074 setXY : function(xy, a, d, c, e){
23076 this.beforeAction();
23078 var cb = this.createCB(c);
23079 supr.setXY.call(this, xy, a, d, cb, e);
23086 createCB : function(c){
23097 // overridden Element method
23098 setX : function(x, a, d, c, e){
23099 this.setXY([x, this.getY()], a, d, c, e);
23102 // overridden Element method
23103 setY : function(y, a, d, c, e){
23104 this.setXY([this.getX(), y], a, d, c, e);
23107 // overridden Element method
23108 setSize : function(w, h, a, d, c, e){
23109 this.beforeAction();
23110 var cb = this.createCB(c);
23111 supr.setSize.call(this, w, h, a, d, cb, e);
23117 // overridden Element method
23118 setWidth : function(w, a, d, c, e){
23119 this.beforeAction();
23120 var cb = this.createCB(c);
23121 supr.setWidth.call(this, w, a, d, cb, e);
23127 // overridden Element method
23128 setHeight : function(h, a, d, c, e){
23129 this.beforeAction();
23130 var cb = this.createCB(c);
23131 supr.setHeight.call(this, h, a, d, cb, e);
23137 // overridden Element method
23138 setBounds : function(x, y, w, h, a, d, c, e){
23139 this.beforeAction();
23140 var cb = this.createCB(c);
23142 this.storeXY([x, y]);
23143 supr.setXY.call(this, [x, y]);
23144 supr.setSize.call(this, w, h, a, d, cb, e);
23147 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23153 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23154 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23155 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23156 * @param {Number} zindex The new z-index to set
23157 * @return {this} The Layer
23159 setZIndex : function(zindex){
23160 this.zindex = zindex;
23161 this.setStyle("z-index", zindex + 2);
23163 this.shadow.setZIndex(zindex + 1);
23166 this.shim.setStyle("z-index", zindex);
23172 * Ext JS Library 1.1.1
23173 * Copyright(c) 2006-2007, Ext JS, LLC.
23175 * Originally Released Under LGPL - original licence link has changed is not relivant.
23178 * <script type="text/javascript">
23183 * @class Roo.Shadow
23184 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
23185 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
23186 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
23188 * Create a new Shadow
23189 * @param {Object} config The config object
23191 Roo.Shadow = function(config){
23192 Roo.apply(this, config);
23193 if(typeof this.mode != "string"){
23194 this.mode = this.defaultMode;
23196 var o = this.offset, a = {h: 0};
23197 var rad = Math.floor(this.offset/2);
23198 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
23204 a.l -= this.offset + rad;
23205 a.t -= this.offset + rad;
23216 a.l -= (this.offset - rad);
23217 a.t -= this.offset + rad;
23219 a.w -= (this.offset - rad)*2;
23230 a.l -= (this.offset - rad);
23231 a.t -= (this.offset - rad);
23233 a.w -= (this.offset + rad + 1);
23234 a.h -= (this.offset + rad);
23243 Roo.Shadow.prototype = {
23245 * @cfg {String} mode
23246 * The shadow display mode. Supports the following options:<br />
23247 * sides: Shadow displays on both sides and bottom only<br />
23248 * frame: Shadow displays equally on all four sides<br />
23249 * drop: Traditional bottom-right drop shadow (default)
23252 * @cfg {String} offset
23253 * The number of pixels to offset the shadow from the element (defaults to 4)
23258 defaultMode: "drop",
23261 * Displays the shadow under the target element
23262 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
23264 show : function(target){
23265 target = Roo.get(target);
23267 this.el = Roo.Shadow.Pool.pull();
23268 if(this.el.dom.nextSibling != target.dom){
23269 this.el.insertBefore(target);
23272 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
23274 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
23277 target.getLeft(true),
23278 target.getTop(true),
23282 this.el.dom.style.display = "block";
23286 * Returns true if the shadow is visible, else false
23288 isVisible : function(){
23289 return this.el ? true : false;
23293 * Direct alignment when values are already available. Show must be called at least once before
23294 * calling this method to ensure it is initialized.
23295 * @param {Number} left The target element left position
23296 * @param {Number} top The target element top position
23297 * @param {Number} width The target element width
23298 * @param {Number} height The target element height
23300 realign : function(l, t, w, h){
23304 var a = this.adjusts, d = this.el.dom, s = d.style;
23306 s.left = (l+a.l)+"px";
23307 s.top = (t+a.t)+"px";
23308 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
23310 if(s.width != sws || s.height != shs){
23314 var cn = d.childNodes;
23315 var sww = Math.max(0, (sw-12))+"px";
23316 cn[0].childNodes[1].style.width = sww;
23317 cn[1].childNodes[1].style.width = sww;
23318 cn[2].childNodes[1].style.width = sww;
23319 cn[1].style.height = Math.max(0, (sh-12))+"px";
23325 * Hides this shadow
23329 this.el.dom.style.display = "none";
23330 Roo.Shadow.Pool.push(this.el);
23336 * Adjust the z-index of this shadow
23337 * @param {Number} zindex The new z-index
23339 setZIndex : function(z){
23342 this.el.setStyle("z-index", z);
23347 // Private utility class that manages the internal Shadow cache
23348 Roo.Shadow.Pool = function(){
23350 var markup = Roo.isIE ?
23351 '<div class="x-ie-shadow"></div>' :
23352 '<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>';
23355 var sh = p.shift();
23357 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
23358 sh.autoBoxAdjust = false;
23363 push : function(sh){
23369 * Ext JS Library 1.1.1
23370 * Copyright(c) 2006-2007, Ext JS, LLC.
23372 * Originally Released Under LGPL - original licence link has changed is not relivant.
23375 * <script type="text/javascript">
23379 * @class Roo.BoxComponent
23380 * @extends Roo.Component
23381 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
23382 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
23383 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
23384 * layout containers.
23386 * @param {Roo.Element/String/Object} config The configuration options.
23388 Roo.BoxComponent = function(config){
23389 Roo.Component.call(this, config);
23393 * Fires after the component is resized.
23394 * @param {Roo.Component} this
23395 * @param {Number} adjWidth The box-adjusted width that was set
23396 * @param {Number} adjHeight The box-adjusted height that was set
23397 * @param {Number} rawWidth The width that was originally specified
23398 * @param {Number} rawHeight The height that was originally specified
23403 * Fires after the component is moved.
23404 * @param {Roo.Component} this
23405 * @param {Number} x The new x position
23406 * @param {Number} y The new y position
23412 Roo.extend(Roo.BoxComponent, Roo.Component, {
23413 // private, set in afterRender to signify that the component has been rendered
23415 // private, used to defer height settings to subclasses
23416 deferHeight: false,
23417 /** @cfg {Number} width
23418 * width (optional) size of component
23420 /** @cfg {Number} height
23421 * height (optional) size of component
23425 * Sets the width and height of the component. This method fires the resize event. This method can accept
23426 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
23427 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
23428 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
23429 * @return {Roo.BoxComponent} this
23431 setSize : function(w, h){
23432 // support for standard size objects
23433 if(typeof w == 'object'){
23438 if(!this.boxReady){
23444 // prevent recalcs when not needed
23445 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23448 this.lastSize = {width: w, height: h};
23450 var adj = this.adjustSize(w, h);
23451 var aw = adj.width, ah = adj.height;
23452 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
23453 var rz = this.getResizeEl();
23454 if(!this.deferHeight && aw !== undefined && ah !== undefined){
23455 rz.setSize(aw, ah);
23456 }else if(!this.deferHeight && ah !== undefined){
23458 }else if(aw !== undefined){
23461 this.onResize(aw, ah, w, h);
23462 this.fireEvent('resize', this, aw, ah, w, h);
23468 * Gets the current size of the component's underlying element.
23469 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
23471 getSize : function(){
23472 return this.el.getSize();
23476 * Gets the current XY position of the component's underlying element.
23477 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23478 * @return {Array} The XY position of the element (e.g., [100, 200])
23480 getPosition : function(local){
23481 if(local === true){
23482 return [this.el.getLeft(true), this.el.getTop(true)];
23484 return this.xy || this.el.getXY();
23488 * Gets the current box measurements of the component's underlying element.
23489 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23490 * @returns {Object} box An object in the format {x, y, width, height}
23492 getBox : function(local){
23493 var s = this.el.getSize();
23495 s.x = this.el.getLeft(true);
23496 s.y = this.el.getTop(true);
23498 var xy = this.xy || this.el.getXY();
23506 * Sets the current box measurements of the component's underlying element.
23507 * @param {Object} box An object in the format {x, y, width, height}
23508 * @returns {Roo.BoxComponent} this
23510 updateBox : function(box){
23511 this.setSize(box.width, box.height);
23512 this.setPagePosition(box.x, box.y);
23517 getResizeEl : function(){
23518 return this.resizeEl || this.el;
23522 getPositionEl : function(){
23523 return this.positionEl || this.el;
23527 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23528 * This method fires the move event.
23529 * @param {Number} left The new left
23530 * @param {Number} top The new top
23531 * @returns {Roo.BoxComponent} this
23533 setPosition : function(x, y){
23536 if(!this.boxReady){
23539 var adj = this.adjustPosition(x, y);
23540 var ax = adj.x, ay = adj.y;
23542 var el = this.getPositionEl();
23543 if(ax !== undefined || ay !== undefined){
23544 if(ax !== undefined && ay !== undefined){
23545 el.setLeftTop(ax, ay);
23546 }else if(ax !== undefined){
23548 }else if(ay !== undefined){
23551 this.onPosition(ax, ay);
23552 this.fireEvent('move', this, ax, ay);
23558 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23559 * This method fires the move event.
23560 * @param {Number} x The new x position
23561 * @param {Number} y The new y position
23562 * @returns {Roo.BoxComponent} this
23564 setPagePosition : function(x, y){
23567 if(!this.boxReady){
23570 if(x === undefined || y === undefined){ // cannot translate undefined points
23573 var p = this.el.translatePoints(x, y);
23574 this.setPosition(p.left, p.top);
23579 onRender : function(ct, position){
23580 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23582 this.resizeEl = Roo.get(this.resizeEl);
23584 if(this.positionEl){
23585 this.positionEl = Roo.get(this.positionEl);
23590 afterRender : function(){
23591 Roo.BoxComponent.superclass.afterRender.call(this);
23592 this.boxReady = true;
23593 this.setSize(this.width, this.height);
23594 if(this.x || this.y){
23595 this.setPosition(this.x, this.y);
23597 if(this.pageX || this.pageY){
23598 this.setPagePosition(this.pageX, this.pageY);
23603 * Force the component's size to recalculate based on the underlying element's current height and width.
23604 * @returns {Roo.BoxComponent} this
23606 syncSize : function(){
23607 delete this.lastSize;
23608 this.setSize(this.el.getWidth(), this.el.getHeight());
23613 * Called after the component is resized, this method is empty by default but can be implemented by any
23614 * subclass that needs to perform custom logic after a resize occurs.
23615 * @param {Number} adjWidth The box-adjusted width that was set
23616 * @param {Number} adjHeight The box-adjusted height that was set
23617 * @param {Number} rawWidth The width that was originally specified
23618 * @param {Number} rawHeight The height that was originally specified
23620 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23625 * Called after the component is moved, this method is empty by default but can be implemented by any
23626 * subclass that needs to perform custom logic after a move occurs.
23627 * @param {Number} x The new x position
23628 * @param {Number} y The new y position
23630 onPosition : function(x, y){
23635 adjustSize : function(w, h){
23636 if(this.autoWidth){
23639 if(this.autoHeight){
23642 return {width : w, height: h};
23646 adjustPosition : function(x, y){
23647 return {x : x, y: y};
23651 * Ext JS Library 1.1.1
23652 * Copyright(c) 2006-2007, Ext JS, LLC.
23654 * Originally Released Under LGPL - original licence link has changed is not relivant.
23657 * <script type="text/javascript">
23662 * @class Roo.SplitBar
23663 * @extends Roo.util.Observable
23664 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23668 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23669 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23670 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23671 split.minSize = 100;
23672 split.maxSize = 600;
23673 split.animate = true;
23674 split.on('moved', splitterMoved);
23677 * Create a new SplitBar
23678 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23679 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23680 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23681 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23682 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23683 position of the SplitBar).
23685 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23688 this.el = Roo.get(dragElement, true);
23689 this.el.dom.unselectable = "on";
23691 this.resizingEl = Roo.get(resizingElement, true);
23695 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23696 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23699 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23702 * The minimum size of the resizing element. (Defaults to 0)
23708 * The maximum size of the resizing element. (Defaults to 2000)
23711 this.maxSize = 2000;
23714 * Whether to animate the transition to the new size
23717 this.animate = false;
23720 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23723 this.useShim = false;
23728 if(!existingProxy){
23730 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23732 this.proxy = Roo.get(existingProxy).dom;
23735 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23738 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23741 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23744 this.dragSpecs = {};
23747 * @private The adapter to use to positon and resize elements
23749 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23750 this.adapter.init(this);
23752 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23754 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23755 this.el.addClass("x-splitbar-h");
23758 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23759 this.el.addClass("x-splitbar-v");
23765 * Fires when the splitter is moved (alias for {@link #event-moved})
23766 * @param {Roo.SplitBar} this
23767 * @param {Number} newSize the new width or height
23772 * Fires when the splitter is moved
23773 * @param {Roo.SplitBar} this
23774 * @param {Number} newSize the new width or height
23778 * @event beforeresize
23779 * Fires before the splitter is dragged
23780 * @param {Roo.SplitBar} this
23782 "beforeresize" : true,
23784 "beforeapply" : true
23787 Roo.util.Observable.call(this);
23790 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23791 onStartProxyDrag : function(x, y){
23792 this.fireEvent("beforeresize", this);
23794 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23796 o.enableDisplayMode("block");
23797 // all splitbars share the same overlay
23798 Roo.SplitBar.prototype.overlay = o;
23800 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23801 this.overlay.show();
23802 Roo.get(this.proxy).setDisplayed("block");
23803 var size = this.adapter.getElementSize(this);
23804 this.activeMinSize = this.getMinimumSize();;
23805 this.activeMaxSize = this.getMaximumSize();;
23806 var c1 = size - this.activeMinSize;
23807 var c2 = Math.max(this.activeMaxSize - size, 0);
23808 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23809 this.dd.resetConstraints();
23810 this.dd.setXConstraint(
23811 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23812 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23814 this.dd.setYConstraint(0, 0);
23816 this.dd.resetConstraints();
23817 this.dd.setXConstraint(0, 0);
23818 this.dd.setYConstraint(
23819 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23820 this.placement == Roo.SplitBar.TOP ? c2 : c1
23823 this.dragSpecs.startSize = size;
23824 this.dragSpecs.startPoint = [x, y];
23825 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23829 * @private Called after the drag operation by the DDProxy
23831 onEndProxyDrag : function(e){
23832 Roo.get(this.proxy).setDisplayed(false);
23833 var endPoint = Roo.lib.Event.getXY(e);
23835 this.overlay.hide();
23838 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23839 newSize = this.dragSpecs.startSize +
23840 (this.placement == Roo.SplitBar.LEFT ?
23841 endPoint[0] - this.dragSpecs.startPoint[0] :
23842 this.dragSpecs.startPoint[0] - endPoint[0]
23845 newSize = this.dragSpecs.startSize +
23846 (this.placement == Roo.SplitBar.TOP ?
23847 endPoint[1] - this.dragSpecs.startPoint[1] :
23848 this.dragSpecs.startPoint[1] - endPoint[1]
23851 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23852 if(newSize != this.dragSpecs.startSize){
23853 if(this.fireEvent('beforeapply', this, newSize) !== false){
23854 this.adapter.setElementSize(this, newSize);
23855 this.fireEvent("moved", this, newSize);
23856 this.fireEvent("resize", this, newSize);
23862 * Get the adapter this SplitBar uses
23863 * @return The adapter object
23865 getAdapter : function(){
23866 return this.adapter;
23870 * Set the adapter this SplitBar uses
23871 * @param {Object} adapter A SplitBar adapter object
23873 setAdapter : function(adapter){
23874 this.adapter = adapter;
23875 this.adapter.init(this);
23879 * Gets the minimum size for the resizing element
23880 * @return {Number} The minimum size
23882 getMinimumSize : function(){
23883 return this.minSize;
23887 * Sets the minimum size for the resizing element
23888 * @param {Number} minSize The minimum size
23890 setMinimumSize : function(minSize){
23891 this.minSize = minSize;
23895 * Gets the maximum size for the resizing element
23896 * @return {Number} The maximum size
23898 getMaximumSize : function(){
23899 return this.maxSize;
23903 * Sets the maximum size for the resizing element
23904 * @param {Number} maxSize The maximum size
23906 setMaximumSize : function(maxSize){
23907 this.maxSize = maxSize;
23911 * Sets the initialize size for the resizing element
23912 * @param {Number} size The initial size
23914 setCurrentSize : function(size){
23915 var oldAnimate = this.animate;
23916 this.animate = false;
23917 this.adapter.setElementSize(this, size);
23918 this.animate = oldAnimate;
23922 * Destroy this splitbar.
23923 * @param {Boolean} removeEl True to remove the element
23925 destroy : function(removeEl){
23927 this.shim.remove();
23930 this.proxy.parentNode.removeChild(this.proxy);
23938 * @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.
23940 Roo.SplitBar.createProxy = function(dir){
23941 var proxy = new Roo.Element(document.createElement("div"));
23942 proxy.unselectable();
23943 var cls = 'x-splitbar-proxy';
23944 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23945 document.body.appendChild(proxy.dom);
23950 * @class Roo.SplitBar.BasicLayoutAdapter
23951 * Default Adapter. It assumes the splitter and resizing element are not positioned
23952 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23954 Roo.SplitBar.BasicLayoutAdapter = function(){
23957 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23958 // do nothing for now
23959 init : function(s){
23963 * Called before drag operations to get the current size of the resizing element.
23964 * @param {Roo.SplitBar} s The SplitBar using this adapter
23966 getElementSize : function(s){
23967 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23968 return s.resizingEl.getWidth();
23970 return s.resizingEl.getHeight();
23975 * Called after drag operations to set the size of the resizing element.
23976 * @param {Roo.SplitBar} s The SplitBar using this adapter
23977 * @param {Number} newSize The new size to set
23978 * @param {Function} onComplete A function to be invoked when resizing is complete
23980 setElementSize : function(s, newSize, onComplete){
23981 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23983 s.resizingEl.setWidth(newSize);
23985 onComplete(s, newSize);
23988 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23993 s.resizingEl.setHeight(newSize);
23995 onComplete(s, newSize);
23998 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24005 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24006 * @extends Roo.SplitBar.BasicLayoutAdapter
24007 * Adapter that moves the splitter element to align with the resized sizing element.
24008 * Used with an absolute positioned SplitBar.
24009 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24010 * document.body, make sure you assign an id to the body element.
24012 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24013 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24014 this.container = Roo.get(container);
24017 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24018 init : function(s){
24019 this.basic.init(s);
24022 getElementSize : function(s){
24023 return this.basic.getElementSize(s);
24026 setElementSize : function(s, newSize, onComplete){
24027 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24030 moveSplitter : function(s){
24031 var yes = Roo.SplitBar;
24032 switch(s.placement){
24034 s.el.setX(s.resizingEl.getRight());
24037 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24040 s.el.setY(s.resizingEl.getBottom());
24043 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24050 * Orientation constant - Create a vertical SplitBar
24054 Roo.SplitBar.VERTICAL = 1;
24057 * Orientation constant - Create a horizontal SplitBar
24061 Roo.SplitBar.HORIZONTAL = 2;
24064 * Placement constant - The resizing element is to the left of the splitter element
24068 Roo.SplitBar.LEFT = 1;
24071 * Placement constant - The resizing element is to the right of the splitter element
24075 Roo.SplitBar.RIGHT = 2;
24078 * Placement constant - The resizing element is positioned above the splitter element
24082 Roo.SplitBar.TOP = 3;
24085 * Placement constant - The resizing element is positioned under splitter element
24089 Roo.SplitBar.BOTTOM = 4;
24092 * Ext JS Library 1.1.1
24093 * Copyright(c) 2006-2007, Ext JS, LLC.
24095 * Originally Released Under LGPL - original licence link has changed is not relivant.
24098 * <script type="text/javascript">
24103 * @extends Roo.util.Observable
24104 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24105 * This class also supports single and multi selection modes. <br>
24106 * Create a data model bound view:
24108 var store = new Roo.data.Store(...);
24110 var view = new Roo.View({
24112 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24114 singleSelect: true,
24115 selectedClass: "ydataview-selected",
24119 // listen for node click?
24120 view.on("click", function(vw, index, node, e){
24121 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24125 dataModel.load("foobar.xml");
24127 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24129 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24130 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24132 * Note: old style constructor is still suported (container, template, config)
24135 * Create a new View
24136 * @param {Object} config The config object
24139 Roo.View = function(config, depreciated_tpl, depreciated_config){
24141 if (typeof(depreciated_tpl) == 'undefined') {
24142 // new way.. - universal constructor.
24143 Roo.apply(this, config);
24144 this.el = Roo.get(this.el);
24147 this.el = Roo.get(config);
24148 this.tpl = depreciated_tpl;
24149 Roo.apply(this, depreciated_config);
24153 if(typeof(this.tpl) == "string"){
24154 this.tpl = new Roo.Template(this.tpl);
24156 // support xtype ctors..
24157 this.tpl = new Roo.factory(this.tpl, Roo);
24161 this.tpl.compile();
24168 * @event beforeclick
24169 * Fires before a click is processed. Returns false to cancel the default action.
24170 * @param {Roo.View} this
24171 * @param {Number} index The index of the target node
24172 * @param {HTMLElement} node The target node
24173 * @param {Roo.EventObject} e The raw event object
24175 "beforeclick" : true,
24178 * Fires when a template node is clicked.
24179 * @param {Roo.View} this
24180 * @param {Number} index The index of the target node
24181 * @param {HTMLElement} node The target node
24182 * @param {Roo.EventObject} e The raw event object
24187 * Fires when a template node is double clicked.
24188 * @param {Roo.View} this
24189 * @param {Number} index The index of the target node
24190 * @param {HTMLElement} node The target node
24191 * @param {Roo.EventObject} e The raw event object
24195 * @event contextmenu
24196 * Fires when a template node is right clicked.
24197 * @param {Roo.View} this
24198 * @param {Number} index The index of the target node
24199 * @param {HTMLElement} node The target node
24200 * @param {Roo.EventObject} e The raw event object
24202 "contextmenu" : true,
24204 * @event selectionchange
24205 * Fires when the selected nodes change.
24206 * @param {Roo.View} this
24207 * @param {Array} selections Array of the selected nodes
24209 "selectionchange" : true,
24212 * @event beforeselect
24213 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24214 * @param {Roo.View} this
24215 * @param {HTMLElement} node The node to be selected
24216 * @param {Array} selections Array of currently selected nodes
24218 "beforeselect" : true,
24220 * @event preparedata
24221 * Fires on every row to render, to allow you to change the data.
24222 * @param {Roo.View} this
24223 * @param {Object} data to be rendered (change this)
24225 "preparedata" : true
24229 "click": this.onClick,
24230 "dblclick": this.onDblClick,
24231 "contextmenu": this.onContextMenu,
24235 this.selections = [];
24237 this.cmp = new Roo.CompositeElementLite([]);
24239 this.store = Roo.factory(this.store, Roo.data);
24240 this.setStore(this.store, true);
24242 Roo.View.superclass.constructor.call(this);
24245 Roo.extend(Roo.View, Roo.util.Observable, {
24248 * @cfg {Roo.data.Store} store Data store to load data from.
24253 * @cfg {String|Roo.Element} el The container element.
24258 * @cfg {String|Roo.Template} tpl The template used by this View
24262 * @cfg {String} dataName the named area of the template to use as the data area
24263 * Works with domtemplates roo-name="name"
24267 * @cfg {String} selectedClass The css class to add to selected nodes
24269 selectedClass : "x-view-selected",
24271 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24275 * @cfg {Boolean} multiSelect Allow multiple selection
24277 multiSelect : false,
24279 * @cfg {Boolean} singleSelect Allow single selection
24281 singleSelect: false,
24284 * @cfg {Boolean} toggleSelect - selecting
24286 toggleSelect : false,
24289 * Returns the element this view is bound to.
24290 * @return {Roo.Element}
24292 getEl : function(){
24297 * Refreshes the view.
24299 refresh : function(){
24302 // if we are using something like 'domtemplate', then
24303 // the what gets used is:
24304 // t.applySubtemplate(NAME, data, wrapping data..)
24305 // the outer template then get' applied with
24306 // the store 'extra data'
24307 // and the body get's added to the
24308 // roo-name="data" node?
24309 // <span class='roo-tpl-{name}'></span> ?????
24313 this.clearSelections();
24314 this.el.update("");
24316 var records = this.store.getRange();
24317 if(records.length < 1) {
24319 // is this valid?? = should it render a template??
24321 this.el.update(this.emptyText);
24325 if (this.dataName) {
24326 this.el.update(t.apply(this.store.meta)); //????
24327 el = this.el.child('.roo-tpl-' + this.dataName);
24330 for(var i = 0, len = records.length; i < len; i++){
24331 var data = this.prepareData(records[i].data, i, records[i]);
24332 this.fireEvent("preparedata", this, data, i, records[i]);
24333 html[html.length] = Roo.util.Format.trim(
24335 t.applySubtemplate(this.dataName, data, this.store.meta) :
24342 el.update(html.join(""));
24343 this.nodes = el.dom.childNodes;
24344 this.updateIndexes(0);
24348 * Function to override to reformat the data that is sent to
24349 * the template for each node.
24350 * DEPRICATED - use the preparedata event handler.
24351 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24352 * a JSON object for an UpdateManager bound view).
24354 prepareData : function(data, index, record)
24356 this.fireEvent("preparedata", this, data, index, record);
24360 onUpdate : function(ds, record){
24361 this.clearSelections();
24362 var index = this.store.indexOf(record);
24363 var n = this.nodes[index];
24364 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24365 n.parentNode.removeChild(n);
24366 this.updateIndexes(index, index);
24372 onAdd : function(ds, records, index)
24374 this.clearSelections();
24375 if(this.nodes.length == 0){
24379 var n = this.nodes[index];
24380 for(var i = 0, len = records.length; i < len; i++){
24381 var d = this.prepareData(records[i].data, i, records[i]);
24383 this.tpl.insertBefore(n, d);
24386 this.tpl.append(this.el, d);
24389 this.updateIndexes(index);
24392 onRemove : function(ds, record, index){
24393 this.clearSelections();
24394 var el = this.dataName ?
24395 this.el.child('.roo-tpl-' + this.dataName) :
24397 el.dom.removeChild(this.nodes[index]);
24398 this.updateIndexes(index);
24402 * Refresh an individual node.
24403 * @param {Number} index
24405 refreshNode : function(index){
24406 this.onUpdate(this.store, this.store.getAt(index));
24409 updateIndexes : function(startIndex, endIndex){
24410 var ns = this.nodes;
24411 startIndex = startIndex || 0;
24412 endIndex = endIndex || ns.length - 1;
24413 for(var i = startIndex; i <= endIndex; i++){
24414 ns[i].nodeIndex = i;
24419 * Changes the data store this view uses and refresh the view.
24420 * @param {Store} store
24422 setStore : function(store, initial){
24423 if(!initial && this.store){
24424 this.store.un("datachanged", this.refresh);
24425 this.store.un("add", this.onAdd);
24426 this.store.un("remove", this.onRemove);
24427 this.store.un("update", this.onUpdate);
24428 this.store.un("clear", this.refresh);
24432 store.on("datachanged", this.refresh, this);
24433 store.on("add", this.onAdd, this);
24434 store.on("remove", this.onRemove, this);
24435 store.on("update", this.onUpdate, this);
24436 store.on("clear", this.refresh, this);
24445 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
24446 * @param {HTMLElement} node
24447 * @return {HTMLElement} The template node
24449 findItemFromChild : function(node){
24450 var el = this.dataName ?
24451 this.el.child('.roo-tpl-' + this.dataName,true) :
24454 if(!node || node.parentNode == el){
24457 var p = node.parentNode;
24458 while(p && p != el){
24459 if(p.parentNode == el){
24468 onClick : function(e){
24469 var item = this.findItemFromChild(e.getTarget());
24471 var index = this.indexOf(item);
24472 if(this.onItemClick(item, index, e) !== false){
24473 this.fireEvent("click", this, index, item, e);
24476 this.clearSelections();
24481 onContextMenu : function(e){
24482 var item = this.findItemFromChild(e.getTarget());
24484 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24489 onDblClick : function(e){
24490 var item = this.findItemFromChild(e.getTarget());
24492 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24496 onItemClick : function(item, index, e)
24498 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24501 if (this.toggleSelect) {
24502 var m = this.isSelected(item) ? 'unselect' : 'select';
24505 _t[m](item, true, false);
24508 if(this.multiSelect || this.singleSelect){
24509 if(this.multiSelect && e.shiftKey && this.lastSelection){
24510 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24512 this.select(item, this.multiSelect && e.ctrlKey);
24513 this.lastSelection = item;
24515 e.preventDefault();
24521 * Get the number of selected nodes.
24524 getSelectionCount : function(){
24525 return this.selections.length;
24529 * Get the currently selected nodes.
24530 * @return {Array} An array of HTMLElements
24532 getSelectedNodes : function(){
24533 return this.selections;
24537 * Get the indexes of the selected nodes.
24540 getSelectedIndexes : function(){
24541 var indexes = [], s = this.selections;
24542 for(var i = 0, len = s.length; i < len; i++){
24543 indexes.push(s[i].nodeIndex);
24549 * Clear all selections
24550 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24552 clearSelections : function(suppressEvent){
24553 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24554 this.cmp.elements = this.selections;
24555 this.cmp.removeClass(this.selectedClass);
24556 this.selections = [];
24557 if(!suppressEvent){
24558 this.fireEvent("selectionchange", this, this.selections);
24564 * Returns true if the passed node is selected
24565 * @param {HTMLElement/Number} node The node or node index
24566 * @return {Boolean}
24568 isSelected : function(node){
24569 var s = this.selections;
24573 node = this.getNode(node);
24574 return s.indexOf(node) !== -1;
24579 * @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
24580 * @param {Boolean} keepExisting (optional) true to keep existing selections
24581 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24583 select : function(nodeInfo, keepExisting, suppressEvent){
24584 if(nodeInfo instanceof Array){
24586 this.clearSelections(true);
24588 for(var i = 0, len = nodeInfo.length; i < len; i++){
24589 this.select(nodeInfo[i], true, true);
24593 var node = this.getNode(nodeInfo);
24594 if(!node || this.isSelected(node)){
24595 return; // already selected.
24598 this.clearSelections(true);
24600 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24601 Roo.fly(node).addClass(this.selectedClass);
24602 this.selections.push(node);
24603 if(!suppressEvent){
24604 this.fireEvent("selectionchange", this, this.selections);
24612 * @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
24613 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24614 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24616 unselect : function(nodeInfo, keepExisting, suppressEvent)
24618 if(nodeInfo instanceof Array){
24619 Roo.each(this.selections, function(s) {
24620 this.unselect(s, nodeInfo);
24624 var node = this.getNode(nodeInfo);
24625 if(!node || !this.isSelected(node)){
24626 Roo.log("not selected");
24627 return; // not selected.
24631 Roo.each(this.selections, function(s) {
24633 Roo.fly(node).removeClass(this.selectedClass);
24640 this.selections= ns;
24641 this.fireEvent("selectionchange", this, this.selections);
24645 * Gets a template node.
24646 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24647 * @return {HTMLElement} The node or null if it wasn't found
24649 getNode : function(nodeInfo){
24650 if(typeof nodeInfo == "string"){
24651 return document.getElementById(nodeInfo);
24652 }else if(typeof nodeInfo == "number"){
24653 return this.nodes[nodeInfo];
24659 * Gets a range template nodes.
24660 * @param {Number} startIndex
24661 * @param {Number} endIndex
24662 * @return {Array} An array of nodes
24664 getNodes : function(start, end){
24665 var ns = this.nodes;
24666 start = start || 0;
24667 end = typeof end == "undefined" ? ns.length - 1 : end;
24670 for(var i = start; i <= end; i++){
24674 for(var i = start; i >= end; i--){
24682 * Finds the index of the passed node
24683 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24684 * @return {Number} The index of the node or -1
24686 indexOf : function(node){
24687 node = this.getNode(node);
24688 if(typeof node.nodeIndex == "number"){
24689 return node.nodeIndex;
24691 var ns = this.nodes;
24692 for(var i = 0, len = ns.length; i < len; i++){
24702 * Ext JS Library 1.1.1
24703 * Copyright(c) 2006-2007, Ext JS, LLC.
24705 * Originally Released Under LGPL - original licence link has changed is not relivant.
24708 * <script type="text/javascript">
24712 * @class Roo.JsonView
24713 * @extends Roo.View
24714 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24716 var view = new Roo.JsonView({
24717 container: "my-element",
24718 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24723 // listen for node click?
24724 view.on("click", function(vw, index, node, e){
24725 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24728 // direct load of JSON data
24729 view.load("foobar.php");
24731 // Example from my blog list
24732 var tpl = new Roo.Template(
24733 '<div class="entry">' +
24734 '<a class="entry-title" href="{link}">{title}</a>' +
24735 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24736 "</div><hr />"
24739 var moreView = new Roo.JsonView({
24740 container : "entry-list",
24744 moreView.on("beforerender", this.sortEntries, this);
24746 url: "/blog/get-posts.php",
24747 params: "allposts=true",
24748 text: "Loading Blog Entries..."
24752 * Note: old code is supported with arguments : (container, template, config)
24756 * Create a new JsonView
24758 * @param {Object} config The config object
24761 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24764 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24766 var um = this.el.getUpdateManager();
24767 um.setRenderer(this);
24768 um.on("update", this.onLoad, this);
24769 um.on("failure", this.onLoadException, this);
24772 * @event beforerender
24773 * Fires before rendering of the downloaded JSON data.
24774 * @param {Roo.JsonView} this
24775 * @param {Object} data The JSON data loaded
24779 * Fires when data is loaded.
24780 * @param {Roo.JsonView} this
24781 * @param {Object} data The JSON data loaded
24782 * @param {Object} response The raw Connect response object
24785 * @event loadexception
24786 * Fires when loading fails.
24787 * @param {Roo.JsonView} this
24788 * @param {Object} response The raw Connect response object
24791 'beforerender' : true,
24793 'loadexception' : true
24796 Roo.extend(Roo.JsonView, Roo.View, {
24798 * @type {String} The root property in the loaded JSON object that contains the data
24803 * Refreshes the view.
24805 refresh : function(){
24806 this.clearSelections();
24807 this.el.update("");
24809 var o = this.jsonData;
24810 if(o && o.length > 0){
24811 for(var i = 0, len = o.length; i < len; i++){
24812 var data = this.prepareData(o[i], i, o);
24813 html[html.length] = this.tpl.apply(data);
24816 html.push(this.emptyText);
24818 this.el.update(html.join(""));
24819 this.nodes = this.el.dom.childNodes;
24820 this.updateIndexes(0);
24824 * 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.
24825 * @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:
24828 url: "your-url.php",
24829 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24830 callback: yourFunction,
24831 scope: yourObject, //(optional scope)
24834 text: "Loading...",
24839 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24840 * 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.
24841 * @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}
24842 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24843 * @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.
24846 var um = this.el.getUpdateManager();
24847 um.update.apply(um, arguments);
24850 render : function(el, response){
24851 this.clearSelections();
24852 this.el.update("");
24855 o = Roo.util.JSON.decode(response.responseText);
24858 o = o[this.jsonRoot];
24863 * The current JSON data or null
24866 this.beforeRender();
24871 * Get the number of records in the current JSON dataset
24874 getCount : function(){
24875 return this.jsonData ? this.jsonData.length : 0;
24879 * Returns the JSON object for the specified node(s)
24880 * @param {HTMLElement/Array} node The node or an array of nodes
24881 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24882 * you get the JSON object for the node
24884 getNodeData : function(node){
24885 if(node instanceof Array){
24887 for(var i = 0, len = node.length; i < len; i++){
24888 data.push(this.getNodeData(node[i]));
24892 return this.jsonData[this.indexOf(node)] || null;
24895 beforeRender : function(){
24896 this.snapshot = this.jsonData;
24898 this.sort.apply(this, this.sortInfo);
24900 this.fireEvent("beforerender", this, this.jsonData);
24903 onLoad : function(el, o){
24904 this.fireEvent("load", this, this.jsonData, o);
24907 onLoadException : function(el, o){
24908 this.fireEvent("loadexception", this, o);
24912 * Filter the data by a specific property.
24913 * @param {String} property A property on your JSON objects
24914 * @param {String/RegExp} value Either string that the property values
24915 * should start with, or a RegExp to test against the property
24917 filter : function(property, value){
24920 var ss = this.snapshot;
24921 if(typeof value == "string"){
24922 var vlen = value.length;
24924 this.clearFilter();
24927 value = value.toLowerCase();
24928 for(var i = 0, len = ss.length; i < len; i++){
24930 if(o[property].substr(0, vlen).toLowerCase() == value){
24934 } else if(value.exec){ // regex?
24935 for(var i = 0, len = ss.length; i < len; i++){
24937 if(value.test(o[property])){
24944 this.jsonData = data;
24950 * Filter by a function. The passed function will be called with each
24951 * object in the current dataset. If the function returns true the value is kept,
24952 * otherwise it is filtered.
24953 * @param {Function} fn
24954 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24956 filterBy : function(fn, scope){
24959 var ss = this.snapshot;
24960 for(var i = 0, len = ss.length; i < len; i++){
24962 if(fn.call(scope || this, o)){
24966 this.jsonData = data;
24972 * Clears the current filter.
24974 clearFilter : function(){
24975 if(this.snapshot && this.jsonData != this.snapshot){
24976 this.jsonData = this.snapshot;
24983 * Sorts the data for this view and refreshes it.
24984 * @param {String} property A property on your JSON objects to sort on
24985 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24986 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24988 sort : function(property, dir, sortType){
24989 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24992 var dsc = dir && dir.toLowerCase() == "desc";
24993 var f = function(o1, o2){
24994 var v1 = sortType ? sortType(o1[p]) : o1[p];
24995 var v2 = sortType ? sortType(o2[p]) : o2[p];
24998 return dsc ? +1 : -1;
24999 } else if(v1 > v2){
25000 return dsc ? -1 : +1;
25005 this.jsonData.sort(f);
25007 if(this.jsonData != this.snapshot){
25008 this.snapshot.sort(f);
25014 * Ext JS Library 1.1.1
25015 * Copyright(c) 2006-2007, Ext JS, LLC.
25017 * Originally Released Under LGPL - original licence link has changed is not relivant.
25020 * <script type="text/javascript">
25025 * @class Roo.ColorPalette
25026 * @extends Roo.Component
25027 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25028 * Here's an example of typical usage:
25030 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25031 cp.render('my-div');
25033 cp.on('select', function(palette, selColor){
25034 // do something with selColor
25038 * Create a new ColorPalette
25039 * @param {Object} config The config object
25041 Roo.ColorPalette = function(config){
25042 Roo.ColorPalette.superclass.constructor.call(this, config);
25046 * Fires when a color is selected
25047 * @param {ColorPalette} this
25048 * @param {String} color The 6-digit color hex code (without the # symbol)
25054 this.on("select", this.handler, this.scope, true);
25057 Roo.extend(Roo.ColorPalette, Roo.Component, {
25059 * @cfg {String} itemCls
25060 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25062 itemCls : "x-color-palette",
25064 * @cfg {String} value
25065 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25066 * the hex codes are case-sensitive.
25069 clickEvent:'click',
25071 ctype: "Roo.ColorPalette",
25074 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25076 allowReselect : false,
25079 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25080 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25081 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25082 * of colors with the width setting until the box is symmetrical.</p>
25083 * <p>You can override individual colors if needed:</p>
25085 var cp = new Roo.ColorPalette();
25086 cp.colors[0] = "FF0000"; // change the first box to red
25089 Or you can provide a custom array of your own for complete control:
25091 var cp = new Roo.ColorPalette();
25092 cp.colors = ["000000", "993300", "333300"];
25097 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25098 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25099 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25100 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25101 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25105 onRender : function(container, position){
25106 var t = new Roo.MasterTemplate(
25107 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25109 var c = this.colors;
25110 for(var i = 0, len = c.length; i < len; i++){
25113 var el = document.createElement("div");
25114 el.className = this.itemCls;
25116 container.dom.insertBefore(el, position);
25117 this.el = Roo.get(el);
25118 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25119 if(this.clickEvent != 'click'){
25120 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25125 afterRender : function(){
25126 Roo.ColorPalette.superclass.afterRender.call(this);
25128 var s = this.value;
25135 handleClick : function(e, t){
25136 e.preventDefault();
25137 if(!this.disabled){
25138 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25139 this.select(c.toUpperCase());
25144 * Selects the specified color in the palette (fires the select event)
25145 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25147 select : function(color){
25148 color = color.replace("#", "");
25149 if(color != this.value || this.allowReselect){
25152 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25154 el.child("a.color-"+color).addClass("x-color-palette-sel");
25155 this.value = color;
25156 this.fireEvent("select", this, color);
25161 * Ext JS Library 1.1.1
25162 * Copyright(c) 2006-2007, Ext JS, LLC.
25164 * Originally Released Under LGPL - original licence link has changed is not relivant.
25167 * <script type="text/javascript">
25171 * @class Roo.DatePicker
25172 * @extends Roo.Component
25173 * Simple date picker class.
25175 * Create a new DatePicker
25176 * @param {Object} config The config object
25178 Roo.DatePicker = function(config){
25179 Roo.DatePicker.superclass.constructor.call(this, config);
25181 this.value = config && config.value ?
25182 config.value.clearTime() : new Date().clearTime();
25187 * Fires when a date is selected
25188 * @param {DatePicker} this
25189 * @param {Date} date The selected date
25193 * @event monthchange
25194 * Fires when the displayed month changes
25195 * @param {DatePicker} this
25196 * @param {Date} date The selected month
25198 'monthchange': true
25202 this.on("select", this.handler, this.scope || this);
25204 // build the disabledDatesRE
25205 if(!this.disabledDatesRE && this.disabledDates){
25206 var dd = this.disabledDates;
25208 for(var i = 0; i < dd.length; i++){
25210 if(i != dd.length-1) re += "|";
25212 this.disabledDatesRE = new RegExp(re + ")");
25216 Roo.extend(Roo.DatePicker, Roo.Component, {
25218 * @cfg {String} todayText
25219 * The text to display on the button that selects the current date (defaults to "Today")
25221 todayText : "Today",
25223 * @cfg {String} okText
25224 * The text to display on the ok button
25226 okText : " OK ", //   to give the user extra clicking room
25228 * @cfg {String} cancelText
25229 * The text to display on the cancel button
25231 cancelText : "Cancel",
25233 * @cfg {String} todayTip
25234 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25236 todayTip : "{0} (Spacebar)",
25238 * @cfg {Date} minDate
25239 * Minimum allowable date (JavaScript date object, defaults to null)
25243 * @cfg {Date} maxDate
25244 * Maximum allowable date (JavaScript date object, defaults to null)
25248 * @cfg {String} minText
25249 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25251 minText : "This date is before the minimum date",
25253 * @cfg {String} maxText
25254 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25256 maxText : "This date is after the maximum date",
25258 * @cfg {String} format
25259 * The default date format string which can be overriden for localization support. The format must be
25260 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25264 * @cfg {Array} disabledDays
25265 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25267 disabledDays : null,
25269 * @cfg {String} disabledDaysText
25270 * The tooltip to display when the date falls on a disabled day (defaults to "")
25272 disabledDaysText : "",
25274 * @cfg {RegExp} disabledDatesRE
25275 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25277 disabledDatesRE : null,
25279 * @cfg {String} disabledDatesText
25280 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25282 disabledDatesText : "",
25284 * @cfg {Boolean} constrainToViewport
25285 * True to constrain the date picker to the viewport (defaults to true)
25287 constrainToViewport : true,
25289 * @cfg {Array} monthNames
25290 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25292 monthNames : Date.monthNames,
25294 * @cfg {Array} dayNames
25295 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25297 dayNames : Date.dayNames,
25299 * @cfg {String} nextText
25300 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25302 nextText: 'Next Month (Control+Right)',
25304 * @cfg {String} prevText
25305 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25307 prevText: 'Previous Month (Control+Left)',
25309 * @cfg {String} monthYearText
25310 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25312 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25314 * @cfg {Number} startDay
25315 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25319 * @cfg {Bool} showClear
25320 * Show a clear button (usefull for date form elements that can be blank.)
25326 * Sets the value of the date field
25327 * @param {Date} value The date to set
25329 setValue : function(value){
25330 var old = this.value;
25332 if (typeof(value) == 'string') {
25334 value = Date.parseDate(value, this.format);
25337 value = new Date();
25340 this.value = value.clearTime(true);
25342 this.update(this.value);
25347 * Gets the current selected value of the date field
25348 * @return {Date} The selected date
25350 getValue : function(){
25355 focus : function(){
25357 this.update(this.activeDate);
25362 onRender : function(container, position){
25365 '<table cellspacing="0">',
25366 '<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>',
25367 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25368 var dn = this.dayNames;
25369 for(var i = 0; i < 7; i++){
25370 var d = this.startDay+i;
25374 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25376 m[m.length] = "</tr></thead><tbody><tr>";
25377 for(var i = 0; i < 42; i++) {
25378 if(i % 7 == 0 && i != 0){
25379 m[m.length] = "</tr><tr>";
25381 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25383 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25384 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25386 var el = document.createElement("div");
25387 el.className = "x-date-picker";
25388 el.innerHTML = m.join("");
25390 container.dom.insertBefore(el, position);
25392 this.el = Roo.get(el);
25393 this.eventEl = Roo.get(el.firstChild);
25395 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
25396 handler: this.showPrevMonth,
25398 preventDefault:true,
25402 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
25403 handler: this.showNextMonth,
25405 preventDefault:true,
25409 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
25411 this.monthPicker = this.el.down('div.x-date-mp');
25412 this.monthPicker.enableDisplayMode('block');
25414 var kn = new Roo.KeyNav(this.eventEl, {
25415 "left" : function(e){
25417 this.showPrevMonth() :
25418 this.update(this.activeDate.add("d", -1));
25421 "right" : function(e){
25423 this.showNextMonth() :
25424 this.update(this.activeDate.add("d", 1));
25427 "up" : function(e){
25429 this.showNextYear() :
25430 this.update(this.activeDate.add("d", -7));
25433 "down" : function(e){
25435 this.showPrevYear() :
25436 this.update(this.activeDate.add("d", 7));
25439 "pageUp" : function(e){
25440 this.showNextMonth();
25443 "pageDown" : function(e){
25444 this.showPrevMonth();
25447 "enter" : function(e){
25448 e.stopPropagation();
25455 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
25457 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
25459 this.el.unselectable();
25461 this.cells = this.el.select("table.x-date-inner tbody td");
25462 this.textNodes = this.el.query("table.x-date-inner tbody span");
25464 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
25466 tooltip: this.monthYearText
25469 this.mbtn.on('click', this.showMonthPicker, this);
25470 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
25473 var today = (new Date()).dateFormat(this.format);
25475 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
25476 if (this.showClear) {
25477 baseTb.add( new Roo.Toolbar.Fill());
25480 text: String.format(this.todayText, today),
25481 tooltip: String.format(this.todayTip, today),
25482 handler: this.selectToday,
25486 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25489 if (this.showClear) {
25491 baseTb.add( new Roo.Toolbar.Fill());
25494 cls: 'x-btn-icon x-btn-clear',
25495 handler: function() {
25497 this.fireEvent("select", this, '');
25507 this.update(this.value);
25510 createMonthPicker : function(){
25511 if(!this.monthPicker.dom.firstChild){
25512 var buf = ['<table border="0" cellspacing="0">'];
25513 for(var i = 0; i < 6; i++){
25515 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25516 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25518 '<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>' :
25519 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25523 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25525 '</button><button type="button" class="x-date-mp-cancel">',
25527 '</button></td></tr>',
25530 this.monthPicker.update(buf.join(''));
25531 this.monthPicker.on('click', this.onMonthClick, this);
25532 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25534 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25535 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25537 this.mpMonths.each(function(m, a, i){
25540 m.dom.xmonth = 5 + Math.round(i * .5);
25542 m.dom.xmonth = Math.round((i-1) * .5);
25548 showMonthPicker : function(){
25549 this.createMonthPicker();
25550 var size = this.el.getSize();
25551 this.monthPicker.setSize(size);
25552 this.monthPicker.child('table').setSize(size);
25554 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25555 this.updateMPMonth(this.mpSelMonth);
25556 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25557 this.updateMPYear(this.mpSelYear);
25559 this.monthPicker.slideIn('t', {duration:.2});
25562 updateMPYear : function(y){
25564 var ys = this.mpYears.elements;
25565 for(var i = 1; i <= 10; i++){
25566 var td = ys[i-1], y2;
25568 y2 = y + Math.round(i * .5);
25569 td.firstChild.innerHTML = y2;
25572 y2 = y - (5-Math.round(i * .5));
25573 td.firstChild.innerHTML = y2;
25576 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25580 updateMPMonth : function(sm){
25581 this.mpMonths.each(function(m, a, i){
25582 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25586 selectMPMonth: function(m){
25590 onMonthClick : function(e, t){
25592 var el = new Roo.Element(t), pn;
25593 if(el.is('button.x-date-mp-cancel')){
25594 this.hideMonthPicker();
25596 else if(el.is('button.x-date-mp-ok')){
25597 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25598 this.hideMonthPicker();
25600 else if(pn = el.up('td.x-date-mp-month', 2)){
25601 this.mpMonths.removeClass('x-date-mp-sel');
25602 pn.addClass('x-date-mp-sel');
25603 this.mpSelMonth = pn.dom.xmonth;
25605 else if(pn = el.up('td.x-date-mp-year', 2)){
25606 this.mpYears.removeClass('x-date-mp-sel');
25607 pn.addClass('x-date-mp-sel');
25608 this.mpSelYear = pn.dom.xyear;
25610 else if(el.is('a.x-date-mp-prev')){
25611 this.updateMPYear(this.mpyear-10);
25613 else if(el.is('a.x-date-mp-next')){
25614 this.updateMPYear(this.mpyear+10);
25618 onMonthDblClick : function(e, t){
25620 var el = new Roo.Element(t), pn;
25621 if(pn = el.up('td.x-date-mp-month', 2)){
25622 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25623 this.hideMonthPicker();
25625 else if(pn = el.up('td.x-date-mp-year', 2)){
25626 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25627 this.hideMonthPicker();
25631 hideMonthPicker : function(disableAnim){
25632 if(this.monthPicker){
25633 if(disableAnim === true){
25634 this.monthPicker.hide();
25636 this.monthPicker.slideOut('t', {duration:.2});
25642 showPrevMonth : function(e){
25643 this.update(this.activeDate.add("mo", -1));
25647 showNextMonth : function(e){
25648 this.update(this.activeDate.add("mo", 1));
25652 showPrevYear : function(){
25653 this.update(this.activeDate.add("y", -1));
25657 showNextYear : function(){
25658 this.update(this.activeDate.add("y", 1));
25662 handleMouseWheel : function(e){
25663 var delta = e.getWheelDelta();
25665 this.showPrevMonth();
25667 } else if(delta < 0){
25668 this.showNextMonth();
25674 handleDateClick : function(e, t){
25676 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25677 this.setValue(new Date(t.dateValue));
25678 this.fireEvent("select", this, this.value);
25683 selectToday : function(){
25684 this.setValue(new Date().clearTime());
25685 this.fireEvent("select", this, this.value);
25689 update : function(date)
25691 var vd = this.activeDate;
25692 this.activeDate = date;
25694 var t = date.getTime();
25695 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25696 this.cells.removeClass("x-date-selected");
25697 this.cells.each(function(c){
25698 if(c.dom.firstChild.dateValue == t){
25699 c.addClass("x-date-selected");
25700 setTimeout(function(){
25701 try{c.dom.firstChild.focus();}catch(e){}
25710 var days = date.getDaysInMonth();
25711 var firstOfMonth = date.getFirstDateOfMonth();
25712 var startingPos = firstOfMonth.getDay()-this.startDay;
25714 if(startingPos <= this.startDay){
25718 var pm = date.add("mo", -1);
25719 var prevStart = pm.getDaysInMonth()-startingPos;
25721 var cells = this.cells.elements;
25722 var textEls = this.textNodes;
25723 days += startingPos;
25725 // convert everything to numbers so it's fast
25726 var day = 86400000;
25727 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25728 var today = new Date().clearTime().getTime();
25729 var sel = date.clearTime().getTime();
25730 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25731 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25732 var ddMatch = this.disabledDatesRE;
25733 var ddText = this.disabledDatesText;
25734 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25735 var ddaysText = this.disabledDaysText;
25736 var format = this.format;
25738 var setCellClass = function(cal, cell){
25740 var t = d.getTime();
25741 cell.firstChild.dateValue = t;
25743 cell.className += " x-date-today";
25744 cell.title = cal.todayText;
25747 cell.className += " x-date-selected";
25748 setTimeout(function(){
25749 try{cell.firstChild.focus();}catch(e){}
25754 cell.className = " x-date-disabled";
25755 cell.title = cal.minText;
25759 cell.className = " x-date-disabled";
25760 cell.title = cal.maxText;
25764 if(ddays.indexOf(d.getDay()) != -1){
25765 cell.title = ddaysText;
25766 cell.className = " x-date-disabled";
25769 if(ddMatch && format){
25770 var fvalue = d.dateFormat(format);
25771 if(ddMatch.test(fvalue)){
25772 cell.title = ddText.replace("%0", fvalue);
25773 cell.className = " x-date-disabled";
25779 for(; i < startingPos; i++) {
25780 textEls[i].innerHTML = (++prevStart);
25781 d.setDate(d.getDate()+1);
25782 cells[i].className = "x-date-prevday";
25783 setCellClass(this, cells[i]);
25785 for(; i < days; i++){
25786 intDay = i - startingPos + 1;
25787 textEls[i].innerHTML = (intDay);
25788 d.setDate(d.getDate()+1);
25789 cells[i].className = "x-date-active";
25790 setCellClass(this, cells[i]);
25793 for(; i < 42; i++) {
25794 textEls[i].innerHTML = (++extraDays);
25795 d.setDate(d.getDate()+1);
25796 cells[i].className = "x-date-nextday";
25797 setCellClass(this, cells[i]);
25800 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25801 this.fireEvent('monthchange', this, date);
25803 if(!this.internalRender){
25804 var main = this.el.dom.firstChild;
25805 var w = main.offsetWidth;
25806 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25807 Roo.fly(main).setWidth(w);
25808 this.internalRender = true;
25809 // opera does not respect the auto grow header center column
25810 // then, after it gets a width opera refuses to recalculate
25811 // without a second pass
25812 if(Roo.isOpera && !this.secondPass){
25813 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25814 this.secondPass = true;
25815 this.update.defer(10, this, [date]);
25823 * Ext JS Library 1.1.1
25824 * Copyright(c) 2006-2007, Ext JS, LLC.
25826 * Originally Released Under LGPL - original licence link has changed is not relivant.
25829 * <script type="text/javascript">
25832 * @class Roo.TabPanel
25833 * @extends Roo.util.Observable
25834 * A lightweight tab container.
25838 // basic tabs 1, built from existing content
25839 var tabs = new Roo.TabPanel("tabs1");
25840 tabs.addTab("script", "View Script");
25841 tabs.addTab("markup", "View Markup");
25842 tabs.activate("script");
25844 // more advanced tabs, built from javascript
25845 var jtabs = new Roo.TabPanel("jtabs");
25846 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25848 // set up the UpdateManager
25849 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25850 var updater = tab2.getUpdateManager();
25851 updater.setDefaultUrl("ajax1.htm");
25852 tab2.on('activate', updater.refresh, updater, true);
25854 // Use setUrl for Ajax loading
25855 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25856 tab3.setUrl("ajax2.htm", null, true);
25859 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25862 jtabs.activate("jtabs-1");
25865 * Create a new TabPanel.
25866 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25867 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25869 Roo.TabPanel = function(container, config){
25871 * The container element for this TabPanel.
25872 * @type Roo.Element
25874 this.el = Roo.get(container, true);
25876 if(typeof config == "boolean"){
25877 this.tabPosition = config ? "bottom" : "top";
25879 Roo.apply(this, config);
25882 if(this.tabPosition == "bottom"){
25883 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25884 this.el.addClass("x-tabs-bottom");
25886 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25887 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25888 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25890 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25892 if(this.tabPosition != "bottom"){
25893 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25894 * @type Roo.Element
25896 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25897 this.el.addClass("x-tabs-top");
25901 this.bodyEl.setStyle("position", "relative");
25903 this.active = null;
25904 this.activateDelegate = this.activate.createDelegate(this);
25909 * Fires when the active tab changes
25910 * @param {Roo.TabPanel} this
25911 * @param {Roo.TabPanelItem} activePanel The new active tab
25915 * @event beforetabchange
25916 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25917 * @param {Roo.TabPanel} this
25918 * @param {Object} e Set cancel to true on this object to cancel the tab change
25919 * @param {Roo.TabPanelItem} tab The tab being changed to
25921 "beforetabchange" : true
25924 Roo.EventManager.onWindowResize(this.onResize, this);
25925 this.cpad = this.el.getPadding("lr");
25926 this.hiddenCount = 0;
25929 // toolbar on the tabbar support...
25930 if (this.toolbar) {
25931 var tcfg = this.toolbar;
25932 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25933 this.toolbar = new Roo.Toolbar(tcfg);
25934 if (Roo.isSafari) {
25935 var tbl = tcfg.container.child('table', true);
25936 tbl.setAttribute('width', '100%');
25943 Roo.TabPanel.superclass.constructor.call(this);
25946 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25948 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25950 tabPosition : "top",
25952 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25954 currentTabWidth : 0,
25956 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25960 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25964 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25966 preferredTabWidth : 175,
25968 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25970 resizeTabs : false,
25972 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25974 monitorResize : true,
25976 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25981 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25982 * @param {String} id The id of the div to use <b>or create</b>
25983 * @param {String} text The text for the tab
25984 * @param {String} content (optional) Content to put in the TabPanelItem body
25985 * @param {Boolean} closable (optional) True to create a close icon on the tab
25986 * @return {Roo.TabPanelItem} The created TabPanelItem
25988 addTab : function(id, text, content, closable){
25989 var item = new Roo.TabPanelItem(this, id, text, closable);
25990 this.addTabItem(item);
25992 item.setContent(content);
25998 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25999 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26000 * @return {Roo.TabPanelItem}
26002 getTab : function(id){
26003 return this.items[id];
26007 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26008 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26010 hideTab : function(id){
26011 var t = this.items[id];
26014 this.hiddenCount++;
26015 this.autoSizeTabs();
26020 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26021 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26023 unhideTab : function(id){
26024 var t = this.items[id];
26026 t.setHidden(false);
26027 this.hiddenCount--;
26028 this.autoSizeTabs();
26033 * Adds an existing {@link Roo.TabPanelItem}.
26034 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26036 addTabItem : function(item){
26037 this.items[item.id] = item;
26038 this.items.push(item);
26039 if(this.resizeTabs){
26040 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26041 this.autoSizeTabs();
26048 * Removes a {@link Roo.TabPanelItem}.
26049 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26051 removeTab : function(id){
26052 var items = this.items;
26053 var tab = items[id];
26054 if(!tab) { return; }
26055 var index = items.indexOf(tab);
26056 if(this.active == tab && items.length > 1){
26057 var newTab = this.getNextAvailable(index);
26062 this.stripEl.dom.removeChild(tab.pnode.dom);
26063 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26064 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26066 items.splice(index, 1);
26067 delete this.items[tab.id];
26068 tab.fireEvent("close", tab);
26069 tab.purgeListeners();
26070 this.autoSizeTabs();
26073 getNextAvailable : function(start){
26074 var items = this.items;
26076 // look for a next tab that will slide over to
26077 // replace the one being removed
26078 while(index < items.length){
26079 var item = items[++index];
26080 if(item && !item.isHidden()){
26084 // if one isn't found select the previous tab (on the left)
26087 var item = items[--index];
26088 if(item && !item.isHidden()){
26096 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26097 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26099 disableTab : function(id){
26100 var tab = this.items[id];
26101 if(tab && this.active != tab){
26107 * Enables a {@link Roo.TabPanelItem} that is disabled.
26108 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26110 enableTab : function(id){
26111 var tab = this.items[id];
26116 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26117 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26118 * @return {Roo.TabPanelItem} The TabPanelItem.
26120 activate : function(id){
26121 var tab = this.items[id];
26125 if(tab == this.active || tab.disabled){
26129 this.fireEvent("beforetabchange", this, e, tab);
26130 if(e.cancel !== true && !tab.disabled){
26132 this.active.hide();
26134 this.active = this.items[id];
26135 this.active.show();
26136 this.fireEvent("tabchange", this, this.active);
26142 * Gets the active {@link Roo.TabPanelItem}.
26143 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26145 getActiveTab : function(){
26146 return this.active;
26150 * Updates the tab body element to fit the height of the container element
26151 * for overflow scrolling
26152 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26154 syncHeight : function(targetHeight){
26155 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26156 var bm = this.bodyEl.getMargins();
26157 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26158 this.bodyEl.setHeight(newHeight);
26162 onResize : function(){
26163 if(this.monitorResize){
26164 this.autoSizeTabs();
26169 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26171 beginUpdate : function(){
26172 this.updating = true;
26176 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26178 endUpdate : function(){
26179 this.updating = false;
26180 this.autoSizeTabs();
26184 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26186 autoSizeTabs : function(){
26187 var count = this.items.length;
26188 var vcount = count - this.hiddenCount;
26189 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26190 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26191 var availWidth = Math.floor(w / vcount);
26192 var b = this.stripBody;
26193 if(b.getWidth() > w){
26194 var tabs = this.items;
26195 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26196 if(availWidth < this.minTabWidth){
26197 /*if(!this.sleft){ // incomplete scrolling code
26198 this.createScrollButtons();
26201 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26204 if(this.currentTabWidth < this.preferredTabWidth){
26205 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26211 * Returns the number of tabs in this TabPanel.
26214 getCount : function(){
26215 return this.items.length;
26219 * Resizes all the tabs to the passed width
26220 * @param {Number} The new width
26222 setTabWidth : function(width){
26223 this.currentTabWidth = width;
26224 for(var i = 0, len = this.items.length; i < len; i++) {
26225 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26230 * Destroys this TabPanel
26231 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26233 destroy : function(removeEl){
26234 Roo.EventManager.removeResizeListener(this.onResize, this);
26235 for(var i = 0, len = this.items.length; i < len; i++){
26236 this.items[i].purgeListeners();
26238 if(removeEl === true){
26239 this.el.update("");
26246 * @class Roo.TabPanelItem
26247 * @extends Roo.util.Observable
26248 * Represents an individual item (tab plus body) in a TabPanel.
26249 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26250 * @param {String} id The id of this TabPanelItem
26251 * @param {String} text The text for the tab of this TabPanelItem
26252 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26254 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26256 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26257 * @type Roo.TabPanel
26259 this.tabPanel = tabPanel;
26261 * The id for this TabPanelItem
26266 this.disabled = false;
26270 this.loaded = false;
26271 this.closable = closable;
26274 * The body element for this TabPanelItem.
26275 * @type Roo.Element
26277 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26278 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26279 this.bodyEl.setStyle("display", "block");
26280 this.bodyEl.setStyle("zoom", "1");
26283 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26285 this.el = Roo.get(els.el, true);
26286 this.inner = Roo.get(els.inner, true);
26287 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26288 this.pnode = Roo.get(els.el.parentNode, true);
26289 this.el.on("mousedown", this.onTabMouseDown, this);
26290 this.el.on("click", this.onTabClick, this);
26293 var c = Roo.get(els.close, true);
26294 c.dom.title = this.closeText;
26295 c.addClassOnOver("close-over");
26296 c.on("click", this.closeClick, this);
26302 * Fires when this tab becomes the active tab.
26303 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26304 * @param {Roo.TabPanelItem} this
26308 * @event beforeclose
26309 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26310 * @param {Roo.TabPanelItem} this
26311 * @param {Object} e Set cancel to true on this object to cancel the close.
26313 "beforeclose": true,
26316 * Fires when this tab is closed.
26317 * @param {Roo.TabPanelItem} this
26321 * @event deactivate
26322 * Fires when this tab is no longer the active tab.
26323 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26324 * @param {Roo.TabPanelItem} this
26326 "deactivate" : true
26328 this.hidden = false;
26330 Roo.TabPanelItem.superclass.constructor.call(this);
26333 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26334 purgeListeners : function(){
26335 Roo.util.Observable.prototype.purgeListeners.call(this);
26336 this.el.removeAllListeners();
26339 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26342 this.pnode.addClass("on");
26345 this.tabPanel.stripWrap.repaint();
26347 this.fireEvent("activate", this.tabPanel, this);
26351 * Returns true if this tab is the active tab.
26352 * @return {Boolean}
26354 isActive : function(){
26355 return this.tabPanel.getActiveTab() == this;
26359 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26362 this.pnode.removeClass("on");
26364 this.fireEvent("deactivate", this.tabPanel, this);
26367 hideAction : function(){
26368 this.bodyEl.hide();
26369 this.bodyEl.setStyle("position", "absolute");
26370 this.bodyEl.setLeft("-20000px");
26371 this.bodyEl.setTop("-20000px");
26374 showAction : function(){
26375 this.bodyEl.setStyle("position", "relative");
26376 this.bodyEl.setTop("");
26377 this.bodyEl.setLeft("");
26378 this.bodyEl.show();
26382 * Set the tooltip for the tab.
26383 * @param {String} tooltip The tab's tooltip
26385 setTooltip : function(text){
26386 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
26387 this.textEl.dom.qtip = text;
26388 this.textEl.dom.removeAttribute('title');
26390 this.textEl.dom.title = text;
26394 onTabClick : function(e){
26395 e.preventDefault();
26396 this.tabPanel.activate(this.id);
26399 onTabMouseDown : function(e){
26400 e.preventDefault();
26401 this.tabPanel.activate(this.id);
26404 getWidth : function(){
26405 return this.inner.getWidth();
26408 setWidth : function(width){
26409 var iwidth = width - this.pnode.getPadding("lr");
26410 this.inner.setWidth(iwidth);
26411 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
26412 this.pnode.setWidth(width);
26416 * Show or hide the tab
26417 * @param {Boolean} hidden True to hide or false to show.
26419 setHidden : function(hidden){
26420 this.hidden = hidden;
26421 this.pnode.setStyle("display", hidden ? "none" : "");
26425 * Returns true if this tab is "hidden"
26426 * @return {Boolean}
26428 isHidden : function(){
26429 return this.hidden;
26433 * Returns the text for this tab
26436 getText : function(){
26440 autoSize : function(){
26441 //this.el.beginMeasure();
26442 this.textEl.setWidth(1);
26443 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
26444 //this.el.endMeasure();
26448 * Sets the text for the tab (Note: this also sets the tooltip text)
26449 * @param {String} text The tab's text and tooltip
26451 setText : function(text){
26453 this.textEl.update(text);
26454 this.setTooltip(text);
26455 if(!this.tabPanel.resizeTabs){
26460 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
26462 activate : function(){
26463 this.tabPanel.activate(this.id);
26467 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
26469 disable : function(){
26470 if(this.tabPanel.active != this){
26471 this.disabled = true;
26472 this.pnode.addClass("disabled");
26477 * Enables this TabPanelItem if it was previously disabled.
26479 enable : function(){
26480 this.disabled = false;
26481 this.pnode.removeClass("disabled");
26485 * Sets the content for this TabPanelItem.
26486 * @param {String} content The content
26487 * @param {Boolean} loadScripts true to look for and load scripts
26489 setContent : function(content, loadScripts){
26490 this.bodyEl.update(content, loadScripts);
26494 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26495 * @return {Roo.UpdateManager} The UpdateManager
26497 getUpdateManager : function(){
26498 return this.bodyEl.getUpdateManager();
26502 * Set a URL to be used to load the content for this TabPanelItem.
26503 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26504 * @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)
26505 * @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)
26506 * @return {Roo.UpdateManager} The UpdateManager
26508 setUrl : function(url, params, loadOnce){
26509 if(this.refreshDelegate){
26510 this.un('activate', this.refreshDelegate);
26512 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26513 this.on("activate", this.refreshDelegate);
26514 return this.bodyEl.getUpdateManager();
26518 _handleRefresh : function(url, params, loadOnce){
26519 if(!loadOnce || !this.loaded){
26520 var updater = this.bodyEl.getUpdateManager();
26521 updater.update(url, params, this._setLoaded.createDelegate(this));
26526 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26527 * Will fail silently if the setUrl method has not been called.
26528 * This does not activate the panel, just updates its content.
26530 refresh : function(){
26531 if(this.refreshDelegate){
26532 this.loaded = false;
26533 this.refreshDelegate();
26538 _setLoaded : function(){
26539 this.loaded = true;
26543 closeClick : function(e){
26546 this.fireEvent("beforeclose", this, o);
26547 if(o.cancel !== true){
26548 this.tabPanel.removeTab(this.id);
26552 * The text displayed in the tooltip for the close icon.
26555 closeText : "Close this tab"
26559 Roo.TabPanel.prototype.createStrip = function(container){
26560 var strip = document.createElement("div");
26561 strip.className = "x-tabs-wrap";
26562 container.appendChild(strip);
26566 Roo.TabPanel.prototype.createStripList = function(strip){
26567 // div wrapper for retard IE
26568 // returns the "tr" element.
26569 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26570 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26571 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26572 return strip.firstChild.firstChild.firstChild.firstChild;
26575 Roo.TabPanel.prototype.createBody = function(container){
26576 var body = document.createElement("div");
26577 Roo.id(body, "tab-body");
26578 Roo.fly(body).addClass("x-tabs-body");
26579 container.appendChild(body);
26583 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26584 var body = Roo.getDom(id);
26586 body = document.createElement("div");
26589 Roo.fly(body).addClass("x-tabs-item-body");
26590 bodyEl.insertBefore(body, bodyEl.firstChild);
26594 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26595 var td = document.createElement("td");
26596 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26597 //stripEl.appendChild(td);
26599 td.className = "x-tabs-closable";
26600 if(!this.closeTpl){
26601 this.closeTpl = new Roo.Template(
26602 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26603 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26604 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26607 var el = this.closeTpl.overwrite(td, {"text": text});
26608 var close = el.getElementsByTagName("div")[0];
26609 var inner = el.getElementsByTagName("em")[0];
26610 return {"el": el, "close": close, "inner": inner};
26613 this.tabTpl = new Roo.Template(
26614 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26615 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26618 var el = this.tabTpl.overwrite(td, {"text": text});
26619 var inner = el.getElementsByTagName("em")[0];
26620 return {"el": el, "inner": inner};
26624 * Ext JS Library 1.1.1
26625 * Copyright(c) 2006-2007, Ext JS, LLC.
26627 * Originally Released Under LGPL - original licence link has changed is not relivant.
26630 * <script type="text/javascript">
26634 * @class Roo.Button
26635 * @extends Roo.util.Observable
26636 * Simple Button class
26637 * @cfg {String} text The button text
26638 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26639 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26640 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26641 * @cfg {Object} scope The scope of the handler
26642 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26643 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26644 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26645 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26646 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26647 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26648 applies if enableToggle = true)
26649 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26650 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26651 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26653 * Create a new button
26654 * @param {Object} config The config object
26656 Roo.Button = function(renderTo, config)
26660 renderTo = config.renderTo || false;
26663 Roo.apply(this, config);
26667 * Fires when this button is clicked
26668 * @param {Button} this
26669 * @param {EventObject} e The click event
26674 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26675 * @param {Button} this
26676 * @param {Boolean} pressed
26681 * Fires when the mouse hovers over the button
26682 * @param {Button} this
26683 * @param {Event} e The event object
26685 'mouseover' : true,
26688 * Fires when the mouse exits the button
26689 * @param {Button} this
26690 * @param {Event} e The event object
26695 * Fires when the button is rendered
26696 * @param {Button} this
26701 this.menu = Roo.menu.MenuMgr.get(this.menu);
26703 // register listeners first!! - so render can be captured..
26704 Roo.util.Observable.call(this);
26706 this.render(renderTo);
26712 Roo.extend(Roo.Button, Roo.util.Observable, {
26718 * Read-only. True if this button is hidden
26723 * Read-only. True if this button is disabled
26728 * Read-only. True if this button is pressed (only if enableToggle = true)
26734 * @cfg {Number} tabIndex
26735 * The DOM tabIndex for this button (defaults to undefined)
26737 tabIndex : undefined,
26740 * @cfg {Boolean} enableToggle
26741 * True to enable pressed/not pressed toggling (defaults to false)
26743 enableToggle: false,
26745 * @cfg {Mixed} menu
26746 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26750 * @cfg {String} menuAlign
26751 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26753 menuAlign : "tl-bl?",
26756 * @cfg {String} iconCls
26757 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26759 iconCls : undefined,
26761 * @cfg {String} type
26762 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26767 menuClassTarget: 'tr',
26770 * @cfg {String} clickEvent
26771 * The type of event to map to the button's event handler (defaults to 'click')
26773 clickEvent : 'click',
26776 * @cfg {Boolean} handleMouseEvents
26777 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26779 handleMouseEvents : true,
26782 * @cfg {String} tooltipType
26783 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26785 tooltipType : 'qtip',
26788 * @cfg {String} cls
26789 * A CSS class to apply to the button's main element.
26793 * @cfg {Roo.Template} template (Optional)
26794 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26795 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26796 * require code modifications if required elements (e.g. a button) aren't present.
26800 render : function(renderTo){
26802 if(this.hideParent){
26803 this.parentEl = Roo.get(renderTo);
26805 if(!this.dhconfig){
26806 if(!this.template){
26807 if(!Roo.Button.buttonTemplate){
26808 // hideous table template
26809 Roo.Button.buttonTemplate = new Roo.Template(
26810 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26811 '<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>',
26812 "</tr></tbody></table>");
26814 this.template = Roo.Button.buttonTemplate;
26816 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26817 var btnEl = btn.child("button:first");
26818 btnEl.on('focus', this.onFocus, this);
26819 btnEl.on('blur', this.onBlur, this);
26821 btn.addClass(this.cls);
26824 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26827 btnEl.addClass(this.iconCls);
26829 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26832 if(this.tabIndex !== undefined){
26833 btnEl.dom.tabIndex = this.tabIndex;
26836 if(typeof this.tooltip == 'object'){
26837 Roo.QuickTips.tips(Roo.apply({
26841 btnEl.dom[this.tooltipType] = this.tooltip;
26845 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26849 this.el.dom.id = this.el.id = this.id;
26852 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26853 this.menu.on("show", this.onMenuShow, this);
26854 this.menu.on("hide", this.onMenuHide, this);
26856 btn.addClass("x-btn");
26857 if(Roo.isIE && !Roo.isIE7){
26858 this.autoWidth.defer(1, this);
26862 if(this.handleMouseEvents){
26863 btn.on("mouseover", this.onMouseOver, this);
26864 btn.on("mouseout", this.onMouseOut, this);
26865 btn.on("mousedown", this.onMouseDown, this);
26867 btn.on(this.clickEvent, this.onClick, this);
26868 //btn.on("mouseup", this.onMouseUp, this);
26875 Roo.ButtonToggleMgr.register(this);
26877 this.el.addClass("x-btn-pressed");
26880 var repeater = new Roo.util.ClickRepeater(btn,
26881 typeof this.repeat == "object" ? this.repeat : {}
26883 repeater.on("click", this.onClick, this);
26886 this.fireEvent('render', this);
26890 * Returns the button's underlying element
26891 * @return {Roo.Element} The element
26893 getEl : function(){
26898 * Destroys this Button and removes any listeners.
26900 destroy : function(){
26901 Roo.ButtonToggleMgr.unregister(this);
26902 this.el.removeAllListeners();
26903 this.purgeListeners();
26908 autoWidth : function(){
26910 this.el.setWidth("auto");
26911 if(Roo.isIE7 && Roo.isStrict){
26912 var ib = this.el.child('button');
26913 if(ib && ib.getWidth() > 20){
26915 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26920 this.el.beginMeasure();
26922 if(this.el.getWidth() < this.minWidth){
26923 this.el.setWidth(this.minWidth);
26926 this.el.endMeasure();
26933 * Assigns this button's click handler
26934 * @param {Function} handler The function to call when the button is clicked
26935 * @param {Object} scope (optional) Scope for the function passed in
26937 setHandler : function(handler, scope){
26938 this.handler = handler;
26939 this.scope = scope;
26943 * Sets this button's text
26944 * @param {String} text The button text
26946 setText : function(text){
26949 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26955 * Gets the text for this button
26956 * @return {String} The button text
26958 getText : function(){
26966 this.hidden = false;
26968 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26976 this.hidden = true;
26978 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26983 * Convenience function for boolean show/hide
26984 * @param {Boolean} visible True to show, false to hide
26986 setVisible: function(visible){
26995 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26996 * @param {Boolean} state (optional) Force a particular state
26998 toggle : function(state){
26999 state = state === undefined ? !this.pressed : state;
27000 if(state != this.pressed){
27002 this.el.addClass("x-btn-pressed");
27003 this.pressed = true;
27004 this.fireEvent("toggle", this, true);
27006 this.el.removeClass("x-btn-pressed");
27007 this.pressed = false;
27008 this.fireEvent("toggle", this, false);
27010 if(this.toggleHandler){
27011 this.toggleHandler.call(this.scope || this, this, state);
27019 focus : function(){
27020 this.el.child('button:first').focus();
27024 * Disable this button
27026 disable : function(){
27028 this.el.addClass("x-btn-disabled");
27030 this.disabled = true;
27034 * Enable this button
27036 enable : function(){
27038 this.el.removeClass("x-btn-disabled");
27040 this.disabled = false;
27044 * Convenience function for boolean enable/disable
27045 * @param {Boolean} enabled True to enable, false to disable
27047 setDisabled : function(v){
27048 this[v !== true ? "enable" : "disable"]();
27052 onClick : function(e){
27054 e.preventDefault();
27059 if(!this.disabled){
27060 if(this.enableToggle){
27063 if(this.menu && !this.menu.isVisible()){
27064 this.menu.show(this.el, this.menuAlign);
27066 this.fireEvent("click", this, e);
27068 this.el.removeClass("x-btn-over");
27069 this.handler.call(this.scope || this, this, e);
27074 onMouseOver : function(e){
27075 if(!this.disabled){
27076 this.el.addClass("x-btn-over");
27077 this.fireEvent('mouseover', this, e);
27081 onMouseOut : function(e){
27082 if(!e.within(this.el, true)){
27083 this.el.removeClass("x-btn-over");
27084 this.fireEvent('mouseout', this, e);
27088 onFocus : function(e){
27089 if(!this.disabled){
27090 this.el.addClass("x-btn-focus");
27094 onBlur : function(e){
27095 this.el.removeClass("x-btn-focus");
27098 onMouseDown : function(e){
27099 if(!this.disabled && e.button == 0){
27100 this.el.addClass("x-btn-click");
27101 Roo.get(document).on('mouseup', this.onMouseUp, this);
27105 onMouseUp : function(e){
27107 this.el.removeClass("x-btn-click");
27108 Roo.get(document).un('mouseup', this.onMouseUp, this);
27112 onMenuShow : function(e){
27113 this.el.addClass("x-btn-menu-active");
27116 onMenuHide : function(e){
27117 this.el.removeClass("x-btn-menu-active");
27121 // Private utility class used by Button
27122 Roo.ButtonToggleMgr = function(){
27125 function toggleGroup(btn, state){
27127 var g = groups[btn.toggleGroup];
27128 for(var i = 0, l = g.length; i < l; i++){
27130 g[i].toggle(false);
27137 register : function(btn){
27138 if(!btn.toggleGroup){
27141 var g = groups[btn.toggleGroup];
27143 g = groups[btn.toggleGroup] = [];
27146 btn.on("toggle", toggleGroup);
27149 unregister : function(btn){
27150 if(!btn.toggleGroup){
27153 var g = groups[btn.toggleGroup];
27156 btn.un("toggle", toggleGroup);
27162 * Ext JS Library 1.1.1
27163 * Copyright(c) 2006-2007, Ext JS, LLC.
27165 * Originally Released Under LGPL - original licence link has changed is not relivant.
27168 * <script type="text/javascript">
27172 * @class Roo.SplitButton
27173 * @extends Roo.Button
27174 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27175 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27176 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27177 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27178 * @cfg {String} arrowTooltip The title attribute of the arrow
27180 * Create a new menu button
27181 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27182 * @param {Object} config The config object
27184 Roo.SplitButton = function(renderTo, config){
27185 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27187 * @event arrowclick
27188 * Fires when this button's arrow is clicked
27189 * @param {SplitButton} this
27190 * @param {EventObject} e The click event
27192 this.addEvents({"arrowclick":true});
27195 Roo.extend(Roo.SplitButton, Roo.Button, {
27196 render : function(renderTo){
27197 // this is one sweet looking template!
27198 var tpl = new Roo.Template(
27199 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27200 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27201 '<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>',
27202 "</tbody></table></td><td>",
27203 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27204 '<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>',
27205 "</tbody></table></td></tr></table>"
27207 var btn = tpl.append(renderTo, [this.text, this.type], true);
27208 var btnEl = btn.child("button");
27210 btn.addClass(this.cls);
27213 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27216 btnEl.addClass(this.iconCls);
27218 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27222 if(this.handleMouseEvents){
27223 btn.on("mouseover", this.onMouseOver, this);
27224 btn.on("mouseout", this.onMouseOut, this);
27225 btn.on("mousedown", this.onMouseDown, this);
27226 btn.on("mouseup", this.onMouseUp, this);
27228 btn.on(this.clickEvent, this.onClick, this);
27230 if(typeof this.tooltip == 'object'){
27231 Roo.QuickTips.tips(Roo.apply({
27235 btnEl.dom[this.tooltipType] = this.tooltip;
27238 if(this.arrowTooltip){
27239 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27248 this.el.addClass("x-btn-pressed");
27250 if(Roo.isIE && !Roo.isIE7){
27251 this.autoWidth.defer(1, this);
27256 this.menu.on("show", this.onMenuShow, this);
27257 this.menu.on("hide", this.onMenuHide, this);
27259 this.fireEvent('render', this);
27263 autoWidth : function(){
27265 var tbl = this.el.child("table:first");
27266 var tbl2 = this.el.child("table:last");
27267 this.el.setWidth("auto");
27268 tbl.setWidth("auto");
27269 if(Roo.isIE7 && Roo.isStrict){
27270 var ib = this.el.child('button:first');
27271 if(ib && ib.getWidth() > 20){
27273 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27278 this.el.beginMeasure();
27280 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27281 tbl.setWidth(this.minWidth-tbl2.getWidth());
27284 this.el.endMeasure();
27287 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27291 * Sets this button's click handler
27292 * @param {Function} handler The function to call when the button is clicked
27293 * @param {Object} scope (optional) Scope for the function passed above
27295 setHandler : function(handler, scope){
27296 this.handler = handler;
27297 this.scope = scope;
27301 * Sets this button's arrow click handler
27302 * @param {Function} handler The function to call when the arrow is clicked
27303 * @param {Object} scope (optional) Scope for the function passed above
27305 setArrowHandler : function(handler, scope){
27306 this.arrowHandler = handler;
27307 this.scope = scope;
27313 focus : function(){
27315 this.el.child("button:first").focus();
27320 onClick : function(e){
27321 e.preventDefault();
27322 if(!this.disabled){
27323 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27324 if(this.menu && !this.menu.isVisible()){
27325 this.menu.show(this.el, this.menuAlign);
27327 this.fireEvent("arrowclick", this, e);
27328 if(this.arrowHandler){
27329 this.arrowHandler.call(this.scope || this, this, e);
27332 this.fireEvent("click", this, e);
27334 this.handler.call(this.scope || this, this, e);
27340 onMouseDown : function(e){
27341 if(!this.disabled){
27342 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27346 onMouseUp : function(e){
27347 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27352 // backwards compat
27353 Roo.MenuButton = Roo.SplitButton;/*
27355 * Ext JS Library 1.1.1
27356 * Copyright(c) 2006-2007, Ext JS, LLC.
27358 * Originally Released Under LGPL - original licence link has changed is not relivant.
27361 * <script type="text/javascript">
27365 * @class Roo.Toolbar
27366 * Basic Toolbar class.
27368 * Creates a new Toolbar
27369 * @param {Object} container The config object
27371 Roo.Toolbar = function(container, buttons, config)
27373 /// old consturctor format still supported..
27374 if(container instanceof Array){ // omit the container for later rendering
27375 buttons = container;
27379 if (typeof(container) == 'object' && container.xtype) {
27380 config = container;
27381 container = config.container;
27382 buttons = config.buttons || []; // not really - use items!!
27385 if (config && config.items) {
27386 xitems = config.items;
27387 delete config.items;
27389 Roo.apply(this, config);
27390 this.buttons = buttons;
27393 this.render(container);
27395 this.xitems = xitems;
27396 Roo.each(xitems, function(b) {
27402 Roo.Toolbar.prototype = {
27404 * @cfg {Array} items
27405 * array of button configs or elements to add (will be converted to a MixedCollection)
27409 * @cfg {String/HTMLElement/Element} container
27410 * The id or element that will contain the toolbar
27413 render : function(ct){
27414 this.el = Roo.get(ct);
27416 this.el.addClass(this.cls);
27418 // using a table allows for vertical alignment
27419 // 100% width is needed by Safari...
27420 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
27421 this.tr = this.el.child("tr", true);
27423 this.items = new Roo.util.MixedCollection(false, function(o){
27424 return o.id || ("item" + (++autoId));
27427 this.add.apply(this, this.buttons);
27428 delete this.buttons;
27433 * Adds element(s) to the toolbar -- this function takes a variable number of
27434 * arguments of mixed type and adds them to the toolbar.
27435 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
27437 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
27438 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
27439 * <li>Field: Any form field (equivalent to {@link #addField})</li>
27440 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
27441 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
27442 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
27443 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
27444 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
27445 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
27447 * @param {Mixed} arg2
27448 * @param {Mixed} etc.
27451 var a = arguments, l = a.length;
27452 for(var i = 0; i < l; i++){
27457 _add : function(el) {
27460 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
27463 if (el.applyTo){ // some kind of form field
27464 return this.addField(el);
27466 if (el.render){ // some kind of Toolbar.Item
27467 return this.addItem(el);
27469 if (typeof el == "string"){ // string
27470 if(el == "separator" || el == "-"){
27471 return this.addSeparator();
27474 return this.addSpacer();
27477 return this.addFill();
27479 return this.addText(el);
27482 if(el.tagName){ // element
27483 return this.addElement(el);
27485 if(typeof el == "object"){ // must be button config?
27486 return this.addButton(el);
27488 // and now what?!?!
27494 * Add an Xtype element
27495 * @param {Object} xtype Xtype Object
27496 * @return {Object} created Object
27498 addxtype : function(e){
27499 return this.add(e);
27503 * Returns the Element for this toolbar.
27504 * @return {Roo.Element}
27506 getEl : function(){
27512 * @return {Roo.Toolbar.Item} The separator item
27514 addSeparator : function(){
27515 return this.addItem(new Roo.Toolbar.Separator());
27519 * Adds a spacer element
27520 * @return {Roo.Toolbar.Spacer} The spacer item
27522 addSpacer : function(){
27523 return this.addItem(new Roo.Toolbar.Spacer());
27527 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27528 * @return {Roo.Toolbar.Fill} The fill item
27530 addFill : function(){
27531 return this.addItem(new Roo.Toolbar.Fill());
27535 * Adds any standard HTML element to the toolbar
27536 * @param {String/HTMLElement/Element} el The element or id of the element to add
27537 * @return {Roo.Toolbar.Item} The element's item
27539 addElement : function(el){
27540 return this.addItem(new Roo.Toolbar.Item(el));
27543 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27544 * @type Roo.util.MixedCollection
27549 * Adds any Toolbar.Item or subclass
27550 * @param {Roo.Toolbar.Item} item
27551 * @return {Roo.Toolbar.Item} The item
27553 addItem : function(item){
27554 var td = this.nextBlock();
27556 this.items.add(item);
27561 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27562 * @param {Object/Array} config A button config or array of configs
27563 * @return {Roo.Toolbar.Button/Array}
27565 addButton : function(config){
27566 if(config instanceof Array){
27568 for(var i = 0, len = config.length; i < len; i++) {
27569 buttons.push(this.addButton(config[i]));
27574 if(!(config instanceof Roo.Toolbar.Button)){
27576 new Roo.Toolbar.SplitButton(config) :
27577 new Roo.Toolbar.Button(config);
27579 var td = this.nextBlock();
27586 * Adds text to the toolbar
27587 * @param {String} text The text to add
27588 * @return {Roo.Toolbar.Item} The element's item
27590 addText : function(text){
27591 return this.addItem(new Roo.Toolbar.TextItem(text));
27595 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27596 * @param {Number} index The index where the item is to be inserted
27597 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27598 * @return {Roo.Toolbar.Button/Item}
27600 insertButton : function(index, item){
27601 if(item instanceof Array){
27603 for(var i = 0, len = item.length; i < len; i++) {
27604 buttons.push(this.insertButton(index + i, item[i]));
27608 if (!(item instanceof Roo.Toolbar.Button)){
27609 item = new Roo.Toolbar.Button(item);
27611 var td = document.createElement("td");
27612 this.tr.insertBefore(td, this.tr.childNodes[index]);
27614 this.items.insert(index, item);
27619 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27620 * @param {Object} config
27621 * @return {Roo.Toolbar.Item} The element's item
27623 addDom : function(config, returnEl){
27624 var td = this.nextBlock();
27625 Roo.DomHelper.overwrite(td, config);
27626 var ti = new Roo.Toolbar.Item(td.firstChild);
27628 this.items.add(ti);
27633 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27634 * @type Roo.util.MixedCollection
27639 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27640 * Note: the field should not have been rendered yet. For a field that has already been
27641 * rendered, use {@link #addElement}.
27642 * @param {Roo.form.Field} field
27643 * @return {Roo.ToolbarItem}
27647 addField : function(field) {
27648 if (!this.fields) {
27650 this.fields = new Roo.util.MixedCollection(false, function(o){
27651 return o.id || ("item" + (++autoId));
27656 var td = this.nextBlock();
27658 var ti = new Roo.Toolbar.Item(td.firstChild);
27660 this.items.add(ti);
27661 this.fields.add(field);
27672 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27673 this.el.child('div').hide();
27681 this.el.child('div').show();
27685 nextBlock : function(){
27686 var td = document.createElement("td");
27687 this.tr.appendChild(td);
27692 destroy : function(){
27693 if(this.items){ // rendered?
27694 Roo.destroy.apply(Roo, this.items.items);
27696 if(this.fields){ // rendered?
27697 Roo.destroy.apply(Roo, this.fields.items);
27699 Roo.Element.uncache(this.el, this.tr);
27704 * @class Roo.Toolbar.Item
27705 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27707 * Creates a new Item
27708 * @param {HTMLElement} el
27710 Roo.Toolbar.Item = function(el){
27711 this.el = Roo.getDom(el);
27712 this.id = Roo.id(this.el);
27713 this.hidden = false;
27716 Roo.Toolbar.Item.prototype = {
27719 * Get this item's HTML Element
27720 * @return {HTMLElement}
27722 getEl : function(){
27727 render : function(td){
27729 td.appendChild(this.el);
27733 * Removes and destroys this item.
27735 destroy : function(){
27736 this.td.parentNode.removeChild(this.td);
27743 this.hidden = false;
27744 this.td.style.display = "";
27751 this.hidden = true;
27752 this.td.style.display = "none";
27756 * Convenience function for boolean show/hide.
27757 * @param {Boolean} visible true to show/false to hide
27759 setVisible: function(visible){
27768 * Try to focus this item.
27770 focus : function(){
27771 Roo.fly(this.el).focus();
27775 * Disables this item.
27777 disable : function(){
27778 Roo.fly(this.td).addClass("x-item-disabled");
27779 this.disabled = true;
27780 this.el.disabled = true;
27784 * Enables this item.
27786 enable : function(){
27787 Roo.fly(this.td).removeClass("x-item-disabled");
27788 this.disabled = false;
27789 this.el.disabled = false;
27795 * @class Roo.Toolbar.Separator
27796 * @extends Roo.Toolbar.Item
27797 * A simple toolbar separator class
27799 * Creates a new Separator
27801 Roo.Toolbar.Separator = function(){
27802 var s = document.createElement("span");
27803 s.className = "ytb-sep";
27804 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27806 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27807 enable:Roo.emptyFn,
27808 disable:Roo.emptyFn,
27813 * @class Roo.Toolbar.Spacer
27814 * @extends Roo.Toolbar.Item
27815 * A simple element that adds extra horizontal space to a toolbar.
27817 * Creates a new Spacer
27819 Roo.Toolbar.Spacer = function(){
27820 var s = document.createElement("div");
27821 s.className = "ytb-spacer";
27822 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27824 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27825 enable:Roo.emptyFn,
27826 disable:Roo.emptyFn,
27831 * @class Roo.Toolbar.Fill
27832 * @extends Roo.Toolbar.Spacer
27833 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27835 * Creates a new Spacer
27837 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27839 render : function(td){
27840 td.style.width = '100%';
27841 Roo.Toolbar.Fill.superclass.render.call(this, td);
27846 * @class Roo.Toolbar.TextItem
27847 * @extends Roo.Toolbar.Item
27848 * A simple class that renders text directly into a toolbar.
27850 * Creates a new TextItem
27851 * @param {String} text
27853 Roo.Toolbar.TextItem = function(text){
27854 if (typeof(text) == 'object') {
27857 var s = document.createElement("span");
27858 s.className = "ytb-text";
27859 s.innerHTML = text;
27860 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27862 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27863 enable:Roo.emptyFn,
27864 disable:Roo.emptyFn,
27869 * @class Roo.Toolbar.Button
27870 * @extends Roo.Button
27871 * A button that renders into a toolbar.
27873 * Creates a new Button
27874 * @param {Object} config A standard {@link Roo.Button} config object
27876 Roo.Toolbar.Button = function(config){
27877 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27879 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27880 render : function(td){
27882 Roo.Toolbar.Button.superclass.render.call(this, td);
27886 * Removes and destroys this button
27888 destroy : function(){
27889 Roo.Toolbar.Button.superclass.destroy.call(this);
27890 this.td.parentNode.removeChild(this.td);
27894 * Shows this button
27897 this.hidden = false;
27898 this.td.style.display = "";
27902 * Hides this button
27905 this.hidden = true;
27906 this.td.style.display = "none";
27910 * Disables this item
27912 disable : function(){
27913 Roo.fly(this.td).addClass("x-item-disabled");
27914 this.disabled = true;
27918 * Enables this item
27920 enable : function(){
27921 Roo.fly(this.td).removeClass("x-item-disabled");
27922 this.disabled = false;
27925 // backwards compat
27926 Roo.ToolbarButton = Roo.Toolbar.Button;
27929 * @class Roo.Toolbar.SplitButton
27930 * @extends Roo.SplitButton
27931 * A menu button that renders into a toolbar.
27933 * Creates a new SplitButton
27934 * @param {Object} config A standard {@link Roo.SplitButton} config object
27936 Roo.Toolbar.SplitButton = function(config){
27937 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27939 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27940 render : function(td){
27942 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27946 * Removes and destroys this button
27948 destroy : function(){
27949 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27950 this.td.parentNode.removeChild(this.td);
27954 * Shows this button
27957 this.hidden = false;
27958 this.td.style.display = "";
27962 * Hides this button
27965 this.hidden = true;
27966 this.td.style.display = "none";
27970 // backwards compat
27971 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27973 * Ext JS Library 1.1.1
27974 * Copyright(c) 2006-2007, Ext JS, LLC.
27976 * Originally Released Under LGPL - original licence link has changed is not relivant.
27979 * <script type="text/javascript">
27983 * @class Roo.PagingToolbar
27984 * @extends Roo.Toolbar
27985 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27987 * Create a new PagingToolbar
27988 * @param {Object} config The config object
27990 Roo.PagingToolbar = function(el, ds, config)
27992 // old args format still supported... - xtype is prefered..
27993 if (typeof(el) == 'object' && el.xtype) {
27994 // created from xtype...
27996 ds = el.dataSource;
27997 el = config.container;
28000 if (config.items) {
28001 items = config.items;
28005 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28008 this.renderButtons(this.el);
28011 // supprot items array.
28013 Roo.each(items, function(e) {
28014 this.add(Roo.factory(e));
28019 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28021 * @cfg {Roo.data.Store} dataSource
28022 * The underlying data store providing the paged data
28025 * @cfg {String/HTMLElement/Element} container
28026 * container The id or element that will contain the toolbar
28029 * @cfg {Boolean} displayInfo
28030 * True to display the displayMsg (defaults to false)
28033 * @cfg {Number} pageSize
28034 * The number of records to display per page (defaults to 20)
28038 * @cfg {String} displayMsg
28039 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28041 displayMsg : 'Displaying {0} - {1} of {2}',
28043 * @cfg {String} emptyMsg
28044 * The message to display when no records are found (defaults to "No data to display")
28046 emptyMsg : 'No data to display',
28048 * Customizable piece of the default paging text (defaults to "Page")
28051 beforePageText : "Page",
28053 * Customizable piece of the default paging text (defaults to "of %0")
28056 afterPageText : "of {0}",
28058 * Customizable piece of the default paging text (defaults to "First Page")
28061 firstText : "First Page",
28063 * Customizable piece of the default paging text (defaults to "Previous Page")
28066 prevText : "Previous Page",
28068 * Customizable piece of the default paging text (defaults to "Next Page")
28071 nextText : "Next Page",
28073 * Customizable piece of the default paging text (defaults to "Last Page")
28076 lastText : "Last Page",
28078 * Customizable piece of the default paging text (defaults to "Refresh")
28081 refreshText : "Refresh",
28084 renderButtons : function(el){
28085 Roo.PagingToolbar.superclass.render.call(this, el);
28086 this.first = this.addButton({
28087 tooltip: this.firstText,
28088 cls: "x-btn-icon x-grid-page-first",
28090 handler: this.onClick.createDelegate(this, ["first"])
28092 this.prev = this.addButton({
28093 tooltip: this.prevText,
28094 cls: "x-btn-icon x-grid-page-prev",
28096 handler: this.onClick.createDelegate(this, ["prev"])
28098 //this.addSeparator();
28099 this.add(this.beforePageText);
28100 this.field = Roo.get(this.addDom({
28105 cls: "x-grid-page-number"
28107 this.field.on("keydown", this.onPagingKeydown, this);
28108 this.field.on("focus", function(){this.dom.select();});
28109 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28110 this.field.setHeight(18);
28111 //this.addSeparator();
28112 this.next = this.addButton({
28113 tooltip: this.nextText,
28114 cls: "x-btn-icon x-grid-page-next",
28116 handler: this.onClick.createDelegate(this, ["next"])
28118 this.last = this.addButton({
28119 tooltip: this.lastText,
28120 cls: "x-btn-icon x-grid-page-last",
28122 handler: this.onClick.createDelegate(this, ["last"])
28124 //this.addSeparator();
28125 this.loading = this.addButton({
28126 tooltip: this.refreshText,
28127 cls: "x-btn-icon x-grid-loading",
28128 handler: this.onClick.createDelegate(this, ["refresh"])
28131 if(this.displayInfo){
28132 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28137 updateInfo : function(){
28138 if(this.displayEl){
28139 var count = this.ds.getCount();
28140 var msg = count == 0 ?
28144 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28146 this.displayEl.update(msg);
28151 onLoad : function(ds, r, o){
28152 this.cursor = o.params ? o.params.start : 0;
28153 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28155 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28156 this.field.dom.value = ap;
28157 this.first.setDisabled(ap == 1);
28158 this.prev.setDisabled(ap == 1);
28159 this.next.setDisabled(ap == ps);
28160 this.last.setDisabled(ap == ps);
28161 this.loading.enable();
28166 getPageData : function(){
28167 var total = this.ds.getTotalCount();
28170 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28171 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28176 onLoadError : function(){
28177 this.loading.enable();
28181 onPagingKeydown : function(e){
28182 var k = e.getKey();
28183 var d = this.getPageData();
28185 var v = this.field.dom.value, pageNum;
28186 if(!v || isNaN(pageNum = parseInt(v, 10))){
28187 this.field.dom.value = d.activePage;
28190 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28191 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28194 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))
28196 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28197 this.field.dom.value = pageNum;
28198 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28201 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28203 var v = this.field.dom.value, pageNum;
28204 var increment = (e.shiftKey) ? 10 : 1;
28205 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28207 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28208 this.field.dom.value = d.activePage;
28211 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28213 this.field.dom.value = parseInt(v, 10) + increment;
28214 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28215 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28222 beforeLoad : function(){
28224 this.loading.disable();
28229 onClick : function(which){
28233 ds.load({params:{start: 0, limit: this.pageSize}});
28236 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28239 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28242 var total = ds.getTotalCount();
28243 var extra = total % this.pageSize;
28244 var lastStart = extra ? (total - extra) : total-this.pageSize;
28245 ds.load({params:{start: lastStart, limit: this.pageSize}});
28248 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28254 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28255 * @param {Roo.data.Store} store The data store to unbind
28257 unbind : function(ds){
28258 ds.un("beforeload", this.beforeLoad, this);
28259 ds.un("load", this.onLoad, this);
28260 ds.un("loadexception", this.onLoadError, this);
28261 ds.un("remove", this.updateInfo, this);
28262 ds.un("add", this.updateInfo, this);
28263 this.ds = undefined;
28267 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28268 * @param {Roo.data.Store} store The data store to bind
28270 bind : function(ds){
28271 ds.on("beforeload", this.beforeLoad, this);
28272 ds.on("load", this.onLoad, this);
28273 ds.on("loadexception", this.onLoadError, this);
28274 ds.on("remove", this.updateInfo, this);
28275 ds.on("add", this.updateInfo, this);
28280 * Ext JS Library 1.1.1
28281 * Copyright(c) 2006-2007, Ext JS, LLC.
28283 * Originally Released Under LGPL - original licence link has changed is not relivant.
28286 * <script type="text/javascript">
28290 * @class Roo.Resizable
28291 * @extends Roo.util.Observable
28292 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28293 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28294 * 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
28295 * the element will be wrapped for you automatically.</p>
28296 * <p>Here is the list of valid resize handles:</p>
28299 ------ -------------------
28308 'hd' horizontal drag
28311 * <p>Here's an example showing the creation of a typical Resizable:</p>
28313 var resizer = new Roo.Resizable("element-id", {
28321 resizer.on("resize", myHandler);
28323 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28324 * resizer.east.setDisplayed(false);</p>
28325 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28326 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28327 * resize operation's new size (defaults to [0, 0])
28328 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28329 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28330 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28331 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28332 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28333 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28334 * @cfg {Number} width The width of the element in pixels (defaults to null)
28335 * @cfg {Number} height The height of the element in pixels (defaults to null)
28336 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28337 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28338 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28339 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28340 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28341 * in favor of the handles config option (defaults to false)
28342 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28343 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28344 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28345 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28346 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28347 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28348 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28349 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28350 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28351 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28352 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28354 * Create a new resizable component
28355 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28356 * @param {Object} config configuration options
28358 Roo.Resizable = function(el, config)
28360 this.el = Roo.get(el);
28362 if(config && config.wrap){
28363 config.resizeChild = this.el;
28364 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28365 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28366 this.el.setStyle("overflow", "hidden");
28367 this.el.setPositioning(config.resizeChild.getPositioning());
28368 config.resizeChild.clearPositioning();
28369 if(!config.width || !config.height){
28370 var csize = config.resizeChild.getSize();
28371 this.el.setSize(csize.width, csize.height);
28373 if(config.pinned && !config.adjustments){
28374 config.adjustments = "auto";
28378 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28379 this.proxy.unselectable();
28380 this.proxy.enableDisplayMode('block');
28382 Roo.apply(this, config);
28385 this.disableTrackOver = true;
28386 this.el.addClass("x-resizable-pinned");
28388 // if the element isn't positioned, make it relative
28389 var position = this.el.getStyle("position");
28390 if(position != "absolute" && position != "fixed"){
28391 this.el.setStyle("position", "relative");
28393 if(!this.handles){ // no handles passed, must be legacy style
28394 this.handles = 's,e,se';
28395 if(this.multiDirectional){
28396 this.handles += ',n,w';
28399 if(this.handles == "all"){
28400 this.handles = "n s e w ne nw se sw";
28402 var hs = this.handles.split(/\s*?[,;]\s*?| /);
28403 var ps = Roo.Resizable.positions;
28404 for(var i = 0, len = hs.length; i < len; i++){
28405 if(hs[i] && ps[hs[i]]){
28406 var pos = ps[hs[i]];
28407 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
28411 this.corner = this.southeast;
28413 // updateBox = the box can move..
28414 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
28415 this.updateBox = true;
28418 this.activeHandle = null;
28420 if(this.resizeChild){
28421 if(typeof this.resizeChild == "boolean"){
28422 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
28424 this.resizeChild = Roo.get(this.resizeChild, true);
28428 if(this.adjustments == "auto"){
28429 var rc = this.resizeChild;
28430 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
28431 if(rc && (hw || hn)){
28432 rc.position("relative");
28433 rc.setLeft(hw ? hw.el.getWidth() : 0);
28434 rc.setTop(hn ? hn.el.getHeight() : 0);
28436 this.adjustments = [
28437 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
28438 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
28442 if(this.draggable){
28443 this.dd = this.dynamic ?
28444 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
28445 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
28451 * @event beforeresize
28452 * Fired before resize is allowed. Set enabled to false to cancel resize.
28453 * @param {Roo.Resizable} this
28454 * @param {Roo.EventObject} e The mousedown event
28456 "beforeresize" : true,
28459 * Fired after a resize.
28460 * @param {Roo.Resizable} this
28461 * @param {Number} width The new width
28462 * @param {Number} height The new height
28463 * @param {Roo.EventObject} e The mouseup event
28468 if(this.width !== null && this.height !== null){
28469 this.resizeTo(this.width, this.height);
28471 this.updateChildSize();
28474 this.el.dom.style.zoom = 1;
28476 Roo.Resizable.superclass.constructor.call(this);
28479 Roo.extend(Roo.Resizable, Roo.util.Observable, {
28480 resizeChild : false,
28481 adjustments : [0, 0],
28491 multiDirectional : false,
28492 disableTrackOver : false,
28493 easing : 'easeOutStrong',
28494 widthIncrement : 0,
28495 heightIncrement : 0,
28499 preserveRatio : false,
28500 transparent: false,
28506 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28508 constrainTo: undefined,
28510 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28512 resizeRegion: undefined,
28516 * Perform a manual resize
28517 * @param {Number} width
28518 * @param {Number} height
28520 resizeTo : function(width, height){
28521 this.el.setSize(width, height);
28522 this.updateChildSize();
28523 this.fireEvent("resize", this, width, height, null);
28527 startSizing : function(e, handle){
28528 this.fireEvent("beforeresize", this, e);
28529 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28532 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28533 this.overlay.unselectable();
28534 this.overlay.enableDisplayMode("block");
28535 this.overlay.on("mousemove", this.onMouseMove, this);
28536 this.overlay.on("mouseup", this.onMouseUp, this);
28538 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28540 this.resizing = true;
28541 this.startBox = this.el.getBox();
28542 this.startPoint = e.getXY();
28543 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28544 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28546 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28547 this.overlay.show();
28549 if(this.constrainTo) {
28550 var ct = Roo.get(this.constrainTo);
28551 this.resizeRegion = ct.getRegion().adjust(
28552 ct.getFrameWidth('t'),
28553 ct.getFrameWidth('l'),
28554 -ct.getFrameWidth('b'),
28555 -ct.getFrameWidth('r')
28559 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28561 this.proxy.setBox(this.startBox);
28563 this.proxy.setStyle('visibility', 'visible');
28569 onMouseDown : function(handle, e){
28572 this.activeHandle = handle;
28573 this.startSizing(e, handle);
28578 onMouseUp : function(e){
28579 var size = this.resizeElement();
28580 this.resizing = false;
28582 this.overlay.hide();
28584 this.fireEvent("resize", this, size.width, size.height, e);
28588 updateChildSize : function(){
28589 if(this.resizeChild){
28591 var child = this.resizeChild;
28592 var adj = this.adjustments;
28593 if(el.dom.offsetWidth){
28594 var b = el.getSize(true);
28595 child.setSize(b.width+adj[0], b.height+adj[1]);
28597 // Second call here for IE
28598 // The first call enables instant resizing and
28599 // the second call corrects scroll bars if they
28602 setTimeout(function(){
28603 if(el.dom.offsetWidth){
28604 var b = el.getSize(true);
28605 child.setSize(b.width+adj[0], b.height+adj[1]);
28613 snap : function(value, inc, min){
28614 if(!inc || !value) return value;
28615 var newValue = value;
28616 var m = value % inc;
28619 newValue = value + (inc-m);
28621 newValue = value - m;
28624 return Math.max(min, newValue);
28628 resizeElement : function(){
28629 var box = this.proxy.getBox();
28630 if(this.updateBox){
28631 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28633 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28635 this.updateChildSize();
28643 constrain : function(v, diff, m, mx){
28646 }else if(v - diff > mx){
28653 onMouseMove : function(e){
28655 try{// try catch so if something goes wrong the user doesn't get hung
28657 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28661 //var curXY = this.startPoint;
28662 var curSize = this.curSize || this.startBox;
28663 var x = this.startBox.x, y = this.startBox.y;
28664 var ox = x, oy = y;
28665 var w = curSize.width, h = curSize.height;
28666 var ow = w, oh = h;
28667 var mw = this.minWidth, mh = this.minHeight;
28668 var mxw = this.maxWidth, mxh = this.maxHeight;
28669 var wi = this.widthIncrement;
28670 var hi = this.heightIncrement;
28672 var eventXY = e.getXY();
28673 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28674 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28676 var pos = this.activeHandle.position;
28681 w = Math.min(Math.max(mw, w), mxw);
28686 h = Math.min(Math.max(mh, h), mxh);
28691 w = Math.min(Math.max(mw, w), mxw);
28692 h = Math.min(Math.max(mh, h), mxh);
28695 diffY = this.constrain(h, diffY, mh, mxh);
28702 var adiffX = Math.abs(diffX);
28703 var sub = (adiffX % wi); // how much
28704 if (sub > (wi/2)) { // far enough to snap
28705 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28707 // remove difference..
28708 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28712 x = Math.max(this.minX, x);
28715 diffX = this.constrain(w, diffX, mw, mxw);
28721 w = Math.min(Math.max(mw, w), mxw);
28722 diffY = this.constrain(h, diffY, mh, mxh);
28727 diffX = this.constrain(w, diffX, mw, mxw);
28728 diffY = this.constrain(h, diffY, mh, mxh);
28735 diffX = this.constrain(w, diffX, mw, mxw);
28737 h = Math.min(Math.max(mh, h), mxh);
28743 var sw = this.snap(w, wi, mw);
28744 var sh = this.snap(h, hi, mh);
28745 if(sw != w || sh != h){
28768 if(this.preserveRatio){
28773 h = Math.min(Math.max(mh, h), mxh);
28778 w = Math.min(Math.max(mw, w), mxw);
28783 w = Math.min(Math.max(mw, w), mxw);
28789 w = Math.min(Math.max(mw, w), mxw);
28795 h = Math.min(Math.max(mh, h), mxh);
28803 h = Math.min(Math.max(mh, h), mxh);
28813 h = Math.min(Math.max(mh, h), mxh);
28821 if (pos == 'hdrag') {
28824 this.proxy.setBounds(x, y, w, h);
28826 this.resizeElement();
28833 handleOver : function(){
28835 this.el.addClass("x-resizable-over");
28840 handleOut : function(){
28841 if(!this.resizing){
28842 this.el.removeClass("x-resizable-over");
28847 * Returns the element this component is bound to.
28848 * @return {Roo.Element}
28850 getEl : function(){
28855 * Returns the resizeChild element (or null).
28856 * @return {Roo.Element}
28858 getResizeChild : function(){
28859 return this.resizeChild;
28863 * Destroys this resizable. If the element was wrapped and
28864 * removeEl is not true then the element remains.
28865 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28867 destroy : function(removeEl){
28868 this.proxy.remove();
28870 this.overlay.removeAllListeners();
28871 this.overlay.remove();
28873 var ps = Roo.Resizable.positions;
28875 if(typeof ps[k] != "function" && this[ps[k]]){
28876 var h = this[ps[k]];
28877 h.el.removeAllListeners();
28882 this.el.update("");
28889 // hash to map config positions to true positions
28890 Roo.Resizable.positions = {
28891 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28896 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28898 // only initialize the template if resizable is used
28899 var tpl = Roo.DomHelper.createTemplate(
28900 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28903 Roo.Resizable.Handle.prototype.tpl = tpl;
28905 this.position = pos;
28907 // show north drag fro topdra
28908 var handlepos = pos == 'hdrag' ? 'north' : pos;
28910 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28911 if (pos == 'hdrag') {
28912 this.el.setStyle('cursor', 'pointer');
28914 this.el.unselectable();
28916 this.el.setOpacity(0);
28918 this.el.on("mousedown", this.onMouseDown, this);
28919 if(!disableTrackOver){
28920 this.el.on("mouseover", this.onMouseOver, this);
28921 this.el.on("mouseout", this.onMouseOut, this);
28926 Roo.Resizable.Handle.prototype = {
28927 afterResize : function(rz){
28931 onMouseDown : function(e){
28932 this.rz.onMouseDown(this, e);
28935 onMouseOver : function(e){
28936 this.rz.handleOver(this, e);
28939 onMouseOut : function(e){
28940 this.rz.handleOut(this, e);
28944 * Ext JS Library 1.1.1
28945 * Copyright(c) 2006-2007, Ext JS, LLC.
28947 * Originally Released Under LGPL - original licence link has changed is not relivant.
28950 * <script type="text/javascript">
28954 * @class Roo.Editor
28955 * @extends Roo.Component
28956 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28958 * Create a new Editor
28959 * @param {Roo.form.Field} field The Field object (or descendant)
28960 * @param {Object} config The config object
28962 Roo.Editor = function(field, config){
28963 Roo.Editor.superclass.constructor.call(this, config);
28964 this.field = field;
28967 * @event beforestartedit
28968 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28969 * false from the handler of this event.
28970 * @param {Editor} this
28971 * @param {Roo.Element} boundEl The underlying element bound to this editor
28972 * @param {Mixed} value The field value being set
28974 "beforestartedit" : true,
28977 * Fires when this editor is displayed
28978 * @param {Roo.Element} boundEl The underlying element bound to this editor
28979 * @param {Mixed} value The starting field value
28981 "startedit" : true,
28983 * @event beforecomplete
28984 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28985 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28986 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28987 * event will not fire since no edit actually occurred.
28988 * @param {Editor} this
28989 * @param {Mixed} value The current field value
28990 * @param {Mixed} startValue The original field value
28992 "beforecomplete" : true,
28995 * Fires after editing is complete and any changed value has been written to the underlying field.
28996 * @param {Editor} this
28997 * @param {Mixed} value The current field value
28998 * @param {Mixed} startValue The original field value
29002 * @event specialkey
29003 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29004 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29005 * @param {Roo.form.Field} this
29006 * @param {Roo.EventObject} e The event object
29008 "specialkey" : true
29012 Roo.extend(Roo.Editor, Roo.Component, {
29014 * @cfg {Boolean/String} autosize
29015 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29016 * or "height" to adopt the height only (defaults to false)
29019 * @cfg {Boolean} revertInvalid
29020 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29021 * validation fails (defaults to true)
29024 * @cfg {Boolean} ignoreNoChange
29025 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29026 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29027 * will never be ignored.
29030 * @cfg {Boolean} hideEl
29031 * False to keep the bound element visible while the editor is displayed (defaults to true)
29034 * @cfg {Mixed} value
29035 * The data value of the underlying field (defaults to "")
29039 * @cfg {String} alignment
29040 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29044 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29045 * for bottom-right shadow (defaults to "frame")
29049 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29053 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29055 completeOnEnter : false,
29057 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29059 cancelOnEsc : false,
29061 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29066 onRender : function(ct, position){
29067 this.el = new Roo.Layer({
29068 shadow: this.shadow,
29074 constrain: this.constrain
29076 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29077 if(this.field.msgTarget != 'title'){
29078 this.field.msgTarget = 'qtip';
29080 this.field.render(this.el);
29082 this.field.el.dom.setAttribute('autocomplete', 'off');
29084 this.field.on("specialkey", this.onSpecialKey, this);
29085 if(this.swallowKeys){
29086 this.field.el.swallowEvent(['keydown','keypress']);
29089 this.field.on("blur", this.onBlur, this);
29090 if(this.field.grow){
29091 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29095 onSpecialKey : function(field, e)
29097 //Roo.log('editor onSpecialKey');
29098 if(this.completeOnEnter && e.getKey() == e.ENTER){
29100 this.completeEdit();
29103 // do not fire special key otherwise it might hide close the editor...
29104 if(e.getKey() == e.ENTER){
29107 if(this.cancelOnEsc && e.getKey() == e.ESC){
29111 this.fireEvent('specialkey', field, e);
29116 * Starts the editing process and shows the editor.
29117 * @param {String/HTMLElement/Element} el The element to edit
29118 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29119 * to the innerHTML of el.
29121 startEdit : function(el, value){
29123 this.completeEdit();
29125 this.boundEl = Roo.get(el);
29126 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29127 if(!this.rendered){
29128 this.render(this.parentEl || document.body);
29130 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29133 this.startValue = v;
29134 this.field.setValue(v);
29136 var sz = this.boundEl.getSize();
29137 switch(this.autoSize){
29139 this.setSize(sz.width, "");
29142 this.setSize("", sz.height);
29145 this.setSize(sz.width, sz.height);
29148 this.el.alignTo(this.boundEl, this.alignment);
29149 this.editing = true;
29151 Roo.QuickTips.disable();
29157 * Sets the height and width of this editor.
29158 * @param {Number} width The new width
29159 * @param {Number} height The new height
29161 setSize : function(w, h){
29162 this.field.setSize(w, h);
29169 * Realigns the editor to the bound field based on the current alignment config value.
29171 realign : function(){
29172 this.el.alignTo(this.boundEl, this.alignment);
29176 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29177 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29179 completeEdit : function(remainVisible){
29183 var v = this.getValue();
29184 if(this.revertInvalid !== false && !this.field.isValid()){
29185 v = this.startValue;
29186 this.cancelEdit(true);
29188 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29189 this.editing = false;
29193 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29194 this.editing = false;
29195 if(this.updateEl && this.boundEl){
29196 this.boundEl.update(v);
29198 if(remainVisible !== true){
29201 this.fireEvent("complete", this, v, this.startValue);
29206 onShow : function(){
29208 if(this.hideEl !== false){
29209 this.boundEl.hide();
29212 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29213 this.fixIEFocus = true;
29214 this.deferredFocus.defer(50, this);
29216 this.field.focus();
29218 this.fireEvent("startedit", this.boundEl, this.startValue);
29221 deferredFocus : function(){
29223 this.field.focus();
29228 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29229 * reverted to the original starting value.
29230 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29231 * cancel (defaults to false)
29233 cancelEdit : function(remainVisible){
29235 this.setValue(this.startValue);
29236 if(remainVisible !== true){
29243 onBlur : function(){
29244 if(this.allowBlur !== true && this.editing){
29245 this.completeEdit();
29250 onHide : function(){
29252 this.completeEdit();
29256 if(this.field.collapse){
29257 this.field.collapse();
29260 if(this.hideEl !== false){
29261 this.boundEl.show();
29264 Roo.QuickTips.enable();
29269 * Sets the data value of the editor
29270 * @param {Mixed} value Any valid value supported by the underlying field
29272 setValue : function(v){
29273 this.field.setValue(v);
29277 * Gets the data value of the editor
29278 * @return {Mixed} The data value
29280 getValue : function(){
29281 return this.field.getValue();
29285 * Ext JS Library 1.1.1
29286 * Copyright(c) 2006-2007, Ext JS, LLC.
29288 * Originally Released Under LGPL - original licence link has changed is not relivant.
29291 * <script type="text/javascript">
29295 * @class Roo.BasicDialog
29296 * @extends Roo.util.Observable
29297 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29299 var dlg = new Roo.BasicDialog("my-dlg", {
29308 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29309 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29310 dlg.addButton('Cancel', dlg.hide, dlg);
29313 <b>A Dialog should always be a direct child of the body element.</b>
29314 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29315 * @cfg {String} title Default text to display in the title bar (defaults to null)
29316 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29317 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29318 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29319 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29320 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29321 * (defaults to null with no animation)
29322 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29323 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29324 * property for valid values (defaults to 'all')
29325 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29326 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29327 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29328 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29329 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29330 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29331 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29332 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29333 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29334 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29335 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29336 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29337 * draggable = true (defaults to false)
29338 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29339 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29340 * shadow (defaults to false)
29341 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29342 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29343 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29344 * @cfg {Array} buttons Array of buttons
29345 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29347 * Create a new BasicDialog.
29348 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29349 * @param {Object} config Configuration options
29351 Roo.BasicDialog = function(el, config){
29352 this.el = Roo.get(el);
29353 var dh = Roo.DomHelper;
29354 if(!this.el && config && config.autoCreate){
29355 if(typeof config.autoCreate == "object"){
29356 if(!config.autoCreate.id){
29357 config.autoCreate.id = el;
29359 this.el = dh.append(document.body,
29360 config.autoCreate, true);
29362 this.el = dh.append(document.body,
29363 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29367 el.setDisplayed(true);
29368 el.hide = this.hideAction;
29370 el.addClass("x-dlg");
29372 Roo.apply(this, config);
29374 this.proxy = el.createProxy("x-dlg-proxy");
29375 this.proxy.hide = this.hideAction;
29376 this.proxy.setOpacity(.5);
29380 el.setWidth(config.width);
29383 el.setHeight(config.height);
29385 this.size = el.getSize();
29386 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
29387 this.xy = [config.x,config.y];
29389 this.xy = el.getCenterXY(true);
29391 /** The header element @type Roo.Element */
29392 this.header = el.child("> .x-dlg-hd");
29393 /** The body element @type Roo.Element */
29394 this.body = el.child("> .x-dlg-bd");
29395 /** The footer element @type Roo.Element */
29396 this.footer = el.child("> .x-dlg-ft");
29399 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
29402 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
29405 this.header.unselectable();
29407 this.header.update(this.title);
29409 // this element allows the dialog to be focused for keyboard event
29410 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
29411 this.focusEl.swallowEvent("click", true);
29413 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
29415 // wrap the body and footer for special rendering
29416 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
29418 this.bwrap.dom.appendChild(this.footer.dom);
29421 this.bg = this.el.createChild({
29422 tag: "div", cls:"x-dlg-bg",
29423 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
29425 this.centerBg = this.bg.child("div.x-dlg-bg-center");
29428 if(this.autoScroll !== false && !this.autoTabs){
29429 this.body.setStyle("overflow", "auto");
29432 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
29434 if(this.closable !== false){
29435 this.el.addClass("x-dlg-closable");
29436 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
29437 this.close.on("click", this.closeClick, this);
29438 this.close.addClassOnOver("x-dlg-close-over");
29440 if(this.collapsible !== false){
29441 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
29442 this.collapseBtn.on("click", this.collapseClick, this);
29443 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
29444 this.header.on("dblclick", this.collapseClick, this);
29446 if(this.resizable !== false){
29447 this.el.addClass("x-dlg-resizable");
29448 this.resizer = new Roo.Resizable(el, {
29449 minWidth: this.minWidth || 80,
29450 minHeight:this.minHeight || 80,
29451 handles: this.resizeHandles || "all",
29454 this.resizer.on("beforeresize", this.beforeResize, this);
29455 this.resizer.on("resize", this.onResize, this);
29457 if(this.draggable !== false){
29458 el.addClass("x-dlg-draggable");
29459 if (!this.proxyDrag) {
29460 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
29463 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
29465 dd.setHandleElId(this.header.id);
29466 dd.endDrag = this.endMove.createDelegate(this);
29467 dd.startDrag = this.startMove.createDelegate(this);
29468 dd.onDrag = this.onDrag.createDelegate(this);
29473 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
29474 this.mask.enableDisplayMode("block");
29476 this.el.addClass("x-dlg-modal");
29479 this.shadow = new Roo.Shadow({
29480 mode : typeof this.shadow == "string" ? this.shadow : "sides",
29481 offset : this.shadowOffset
29484 this.shadowOffset = 0;
29486 if(Roo.useShims && this.shim !== false){
29487 this.shim = this.el.createShim();
29488 this.shim.hide = this.hideAction;
29496 if (this.buttons) {
29497 var bts= this.buttons;
29499 Roo.each(bts, function(b) {
29508 * Fires when a key is pressed
29509 * @param {Roo.BasicDialog} this
29510 * @param {Roo.EventObject} e
29515 * Fires when this dialog is moved by the user.
29516 * @param {Roo.BasicDialog} this
29517 * @param {Number} x The new page X
29518 * @param {Number} y The new page Y
29523 * Fires when this dialog is resized by the user.
29524 * @param {Roo.BasicDialog} this
29525 * @param {Number} width The new width
29526 * @param {Number} height The new height
29530 * @event beforehide
29531 * Fires before this dialog is hidden.
29532 * @param {Roo.BasicDialog} this
29534 "beforehide" : true,
29537 * Fires when this dialog is hidden.
29538 * @param {Roo.BasicDialog} this
29542 * @event beforeshow
29543 * Fires before this dialog is shown.
29544 * @param {Roo.BasicDialog} this
29546 "beforeshow" : true,
29549 * Fires when this dialog is shown.
29550 * @param {Roo.BasicDialog} this
29554 el.on("keydown", this.onKeyDown, this);
29555 el.on("mousedown", this.toFront, this);
29556 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29558 Roo.DialogManager.register(this);
29559 Roo.BasicDialog.superclass.constructor.call(this);
29562 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29563 shadowOffset: Roo.isIE ? 6 : 5,
29566 minButtonWidth: 75,
29567 defaultButton: null,
29568 buttonAlign: "right",
29573 * Sets the dialog title text
29574 * @param {String} text The title text to display
29575 * @return {Roo.BasicDialog} this
29577 setTitle : function(text){
29578 this.header.update(text);
29583 closeClick : function(){
29588 collapseClick : function(){
29589 this[this.collapsed ? "expand" : "collapse"]();
29593 * Collapses the dialog to its minimized state (only the title bar is visible).
29594 * Equivalent to the user clicking the collapse dialog button.
29596 collapse : function(){
29597 if(!this.collapsed){
29598 this.collapsed = true;
29599 this.el.addClass("x-dlg-collapsed");
29600 this.restoreHeight = this.el.getHeight();
29601 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29606 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29607 * clicking the expand dialog button.
29609 expand : function(){
29610 if(this.collapsed){
29611 this.collapsed = false;
29612 this.el.removeClass("x-dlg-collapsed");
29613 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29618 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29619 * @return {Roo.TabPanel} The tabs component
29621 initTabs : function(){
29622 var tabs = this.getTabs();
29623 while(tabs.getTab(0)){
29626 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29628 tabs.addTab(Roo.id(dom), dom.title);
29636 beforeResize : function(){
29637 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29641 onResize : function(){
29642 this.refreshSize();
29643 this.syncBodyHeight();
29644 this.adjustAssets();
29646 this.fireEvent("resize", this, this.size.width, this.size.height);
29650 onKeyDown : function(e){
29651 if(this.isVisible()){
29652 this.fireEvent("keydown", this, e);
29657 * Resizes the dialog.
29658 * @param {Number} width
29659 * @param {Number} height
29660 * @return {Roo.BasicDialog} this
29662 resizeTo : function(width, height){
29663 this.el.setSize(width, height);
29664 this.size = {width: width, height: height};
29665 this.syncBodyHeight();
29666 if(this.fixedcenter){
29669 if(this.isVisible()){
29670 this.constrainXY();
29671 this.adjustAssets();
29673 this.fireEvent("resize", this, width, height);
29679 * Resizes the dialog to fit the specified content size.
29680 * @param {Number} width
29681 * @param {Number} height
29682 * @return {Roo.BasicDialog} this
29684 setContentSize : function(w, h){
29685 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29686 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29687 //if(!this.el.isBorderBox()){
29688 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29689 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29692 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29693 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29695 this.resizeTo(w, h);
29700 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29701 * executed in response to a particular key being pressed while the dialog is active.
29702 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29703 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29704 * @param {Function} fn The function to call
29705 * @param {Object} scope (optional) The scope of the function
29706 * @return {Roo.BasicDialog} this
29708 addKeyListener : function(key, fn, scope){
29709 var keyCode, shift, ctrl, alt;
29710 if(typeof key == "object" && !(key instanceof Array)){
29711 keyCode = key["key"];
29712 shift = key["shift"];
29713 ctrl = key["ctrl"];
29718 var handler = function(dlg, e){
29719 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29720 var k = e.getKey();
29721 if(keyCode instanceof Array){
29722 for(var i = 0, len = keyCode.length; i < len; i++){
29723 if(keyCode[i] == k){
29724 fn.call(scope || window, dlg, k, e);
29730 fn.call(scope || window, dlg, k, e);
29735 this.on("keydown", handler);
29740 * Returns the TabPanel component (creates it if it doesn't exist).
29741 * Note: If you wish to simply check for the existence of tabs without creating them,
29742 * check for a null 'tabs' property.
29743 * @return {Roo.TabPanel} The tabs component
29745 getTabs : function(){
29747 this.el.addClass("x-dlg-auto-tabs");
29748 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29749 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29755 * Adds a button to the footer section of the dialog.
29756 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29757 * object or a valid Roo.DomHelper element config
29758 * @param {Function} handler The function called when the button is clicked
29759 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29760 * @return {Roo.Button} The new button
29762 addButton : function(config, handler, scope){
29763 var dh = Roo.DomHelper;
29765 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29767 if(!this.btnContainer){
29768 var tb = this.footer.createChild({
29770 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29771 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29773 this.btnContainer = tb.firstChild.firstChild.firstChild;
29778 minWidth: this.minButtonWidth,
29781 if(typeof config == "string"){
29782 bconfig.text = config;
29785 bconfig.dhconfig = config;
29787 Roo.apply(bconfig, config);
29791 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29792 bconfig.position = Math.max(0, bconfig.position);
29793 fc = this.btnContainer.childNodes[bconfig.position];
29796 var btn = new Roo.Button(
29798 this.btnContainer.insertBefore(document.createElement("td"),fc)
29799 : this.btnContainer.appendChild(document.createElement("td")),
29800 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29803 this.syncBodyHeight();
29806 * Array of all the buttons that have been added to this dialog via addButton
29811 this.buttons.push(btn);
29816 * Sets the default button to be focused when the dialog is displayed.
29817 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29818 * @return {Roo.BasicDialog} this
29820 setDefaultButton : function(btn){
29821 this.defaultButton = btn;
29826 getHeaderFooterHeight : function(safe){
29829 height += this.header.getHeight();
29832 var fm = this.footer.getMargins();
29833 height += (this.footer.getHeight()+fm.top+fm.bottom);
29835 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29836 height += this.centerBg.getPadding("tb");
29841 syncBodyHeight : function(){
29842 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29843 var height = this.size.height - this.getHeaderFooterHeight(false);
29844 bd.setHeight(height-bd.getMargins("tb"));
29845 var hh = this.header.getHeight();
29846 var h = this.size.height-hh;
29848 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29849 bw.setHeight(h-cb.getPadding("tb"));
29850 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29851 bd.setWidth(bw.getWidth(true));
29853 this.tabs.syncHeight();
29855 this.tabs.el.repaint();
29861 * Restores the previous state of the dialog if Roo.state is configured.
29862 * @return {Roo.BasicDialog} this
29864 restoreState : function(){
29865 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29866 if(box && box.width){
29867 this.xy = [box.x, box.y];
29868 this.resizeTo(box.width, box.height);
29874 beforeShow : function(){
29876 if(this.fixedcenter){
29877 this.xy = this.el.getCenterXY(true);
29880 Roo.get(document.body).addClass("x-body-masked");
29881 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29884 this.constrainXY();
29888 animShow : function(){
29889 var b = Roo.get(this.animateTarget).getBox();
29890 this.proxy.setSize(b.width, b.height);
29891 this.proxy.setLocation(b.x, b.y);
29893 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29894 true, .35, this.showEl.createDelegate(this));
29898 * Shows the dialog.
29899 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29900 * @return {Roo.BasicDialog} this
29902 show : function(animateTarget){
29903 if (this.fireEvent("beforeshow", this) === false){
29906 if(this.syncHeightBeforeShow){
29907 this.syncBodyHeight();
29908 }else if(this.firstShow){
29909 this.firstShow = false;
29910 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29912 this.animateTarget = animateTarget || this.animateTarget;
29913 if(!this.el.isVisible()){
29915 if(this.animateTarget && Roo.get(this.animateTarget)){
29925 showEl : function(){
29927 this.el.setXY(this.xy);
29929 this.adjustAssets(true);
29932 // IE peekaboo bug - fix found by Dave Fenwick
29936 this.fireEvent("show", this);
29940 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29941 * dialog itself will receive focus.
29943 focus : function(){
29944 if(this.defaultButton){
29945 this.defaultButton.focus();
29947 this.focusEl.focus();
29952 constrainXY : function(){
29953 if(this.constraintoviewport !== false){
29954 if(!this.viewSize){
29955 if(this.container){
29956 var s = this.container.getSize();
29957 this.viewSize = [s.width, s.height];
29959 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29962 var s = Roo.get(this.container||document).getScroll();
29964 var x = this.xy[0], y = this.xy[1];
29965 var w = this.size.width, h = this.size.height;
29966 var vw = this.viewSize[0], vh = this.viewSize[1];
29967 // only move it if it needs it
29969 // first validate right/bottom
29970 if(x + w > vw+s.left){
29974 if(y + h > vh+s.top){
29978 // then make sure top/left isn't negative
29990 if(this.isVisible()){
29991 this.el.setLocation(x, y);
29992 this.adjustAssets();
29999 onDrag : function(){
30000 if(!this.proxyDrag){
30001 this.xy = this.el.getXY();
30002 this.adjustAssets();
30007 adjustAssets : function(doShow){
30008 var x = this.xy[0], y = this.xy[1];
30009 var w = this.size.width, h = this.size.height;
30010 if(doShow === true){
30012 this.shadow.show(this.el);
30018 if(this.shadow && this.shadow.isVisible()){
30019 this.shadow.show(this.el);
30021 if(this.shim && this.shim.isVisible()){
30022 this.shim.setBounds(x, y, w, h);
30027 adjustViewport : function(w, h){
30029 w = Roo.lib.Dom.getViewWidth();
30030 h = Roo.lib.Dom.getViewHeight();
30033 this.viewSize = [w, h];
30034 if(this.modal && this.mask.isVisible()){
30035 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30036 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30038 if(this.isVisible()){
30039 this.constrainXY();
30044 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30045 * shadow, proxy, mask, etc.) Also removes all event listeners.
30046 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30048 destroy : function(removeEl){
30049 if(this.isVisible()){
30050 this.animateTarget = null;
30053 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30055 this.tabs.destroy(removeEl);
30068 for(var i = 0, len = this.buttons.length; i < len; i++){
30069 this.buttons[i].destroy();
30072 this.el.removeAllListeners();
30073 if(removeEl === true){
30074 this.el.update("");
30077 Roo.DialogManager.unregister(this);
30081 startMove : function(){
30082 if(this.proxyDrag){
30085 if(this.constraintoviewport !== false){
30086 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30091 endMove : function(){
30092 if(!this.proxyDrag){
30093 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30095 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30098 this.refreshSize();
30099 this.adjustAssets();
30101 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30105 * Brings this dialog to the front of any other visible dialogs
30106 * @return {Roo.BasicDialog} this
30108 toFront : function(){
30109 Roo.DialogManager.bringToFront(this);
30114 * Sends this dialog to the back (under) of any other visible dialogs
30115 * @return {Roo.BasicDialog} this
30117 toBack : function(){
30118 Roo.DialogManager.sendToBack(this);
30123 * Centers this dialog in the viewport
30124 * @return {Roo.BasicDialog} this
30126 center : function(){
30127 var xy = this.el.getCenterXY(true);
30128 this.moveTo(xy[0], xy[1]);
30133 * Moves the dialog's top-left corner to the specified point
30134 * @param {Number} x
30135 * @param {Number} y
30136 * @return {Roo.BasicDialog} this
30138 moveTo : function(x, y){
30140 if(this.isVisible()){
30141 this.el.setXY(this.xy);
30142 this.adjustAssets();
30148 * Aligns the dialog to the specified element
30149 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30150 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30151 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30152 * @return {Roo.BasicDialog} this
30154 alignTo : function(element, position, offsets){
30155 this.xy = this.el.getAlignToXY(element, position, offsets);
30156 if(this.isVisible()){
30157 this.el.setXY(this.xy);
30158 this.adjustAssets();
30164 * Anchors an element to another element and realigns it when the window is resized.
30165 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30166 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30167 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30168 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30169 * is a number, it is used as the buffer delay (defaults to 50ms).
30170 * @return {Roo.BasicDialog} this
30172 anchorTo : function(el, alignment, offsets, monitorScroll){
30173 var action = function(){
30174 this.alignTo(el, alignment, offsets);
30176 Roo.EventManager.onWindowResize(action, this);
30177 var tm = typeof monitorScroll;
30178 if(tm != 'undefined'){
30179 Roo.EventManager.on(window, 'scroll', action, this,
30180 {buffer: tm == 'number' ? monitorScroll : 50});
30187 * Returns true if the dialog is visible
30188 * @return {Boolean}
30190 isVisible : function(){
30191 return this.el.isVisible();
30195 animHide : function(callback){
30196 var b = Roo.get(this.animateTarget).getBox();
30198 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30200 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30201 this.hideEl.createDelegate(this, [callback]));
30205 * Hides the dialog.
30206 * @param {Function} callback (optional) Function to call when the dialog is hidden
30207 * @return {Roo.BasicDialog} this
30209 hide : function(callback){
30210 if (this.fireEvent("beforehide", this) === false){
30214 this.shadow.hide();
30219 // sometimes animateTarget seems to get set.. causing problems...
30220 // this just double checks..
30221 if(this.animateTarget && Roo.get(this.animateTarget)) {
30222 this.animHide(callback);
30225 this.hideEl(callback);
30231 hideEl : function(callback){
30235 Roo.get(document.body).removeClass("x-body-masked");
30237 this.fireEvent("hide", this);
30238 if(typeof callback == "function"){
30244 hideAction : function(){
30245 this.setLeft("-10000px");
30246 this.setTop("-10000px");
30247 this.setStyle("visibility", "hidden");
30251 refreshSize : function(){
30252 this.size = this.el.getSize();
30253 this.xy = this.el.getXY();
30254 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30258 // z-index is managed by the DialogManager and may be overwritten at any time
30259 setZIndex : function(index){
30261 this.mask.setStyle("z-index", index);
30264 this.shim.setStyle("z-index", ++index);
30267 this.shadow.setZIndex(++index);
30269 this.el.setStyle("z-index", ++index);
30271 this.proxy.setStyle("z-index", ++index);
30274 this.resizer.proxy.setStyle("z-index", ++index);
30277 this.lastZIndex = index;
30281 * Returns the element for this dialog
30282 * @return {Roo.Element} The underlying dialog Element
30284 getEl : function(){
30290 * @class Roo.DialogManager
30291 * Provides global access to BasicDialogs that have been created and
30292 * support for z-indexing (layering) multiple open dialogs.
30294 Roo.DialogManager = function(){
30296 var accessList = [];
30300 var sortDialogs = function(d1, d2){
30301 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30305 var orderDialogs = function(){
30306 accessList.sort(sortDialogs);
30307 var seed = Roo.DialogManager.zseed;
30308 for(var i = 0, len = accessList.length; i < len; i++){
30309 var dlg = accessList[i];
30311 dlg.setZIndex(seed + (i*10));
30318 * The starting z-index for BasicDialogs (defaults to 9000)
30319 * @type Number The z-index value
30324 register : function(dlg){
30325 list[dlg.id] = dlg;
30326 accessList.push(dlg);
30330 unregister : function(dlg){
30331 delete list[dlg.id];
30334 if(!accessList.indexOf){
30335 for( i = 0, len = accessList.length; i < len; i++){
30336 if(accessList[i] == dlg){
30337 accessList.splice(i, 1);
30342 i = accessList.indexOf(dlg);
30344 accessList.splice(i, 1);
30350 * Gets a registered dialog by id
30351 * @param {String/Object} id The id of the dialog or a dialog
30352 * @return {Roo.BasicDialog} this
30354 get : function(id){
30355 return typeof id == "object" ? id : list[id];
30359 * Brings the specified dialog to the front
30360 * @param {String/Object} dlg The id of the dialog or a dialog
30361 * @return {Roo.BasicDialog} this
30363 bringToFront : function(dlg){
30364 dlg = this.get(dlg);
30367 dlg._lastAccess = new Date().getTime();
30374 * Sends the specified dialog to the back
30375 * @param {String/Object} dlg The id of the dialog or a dialog
30376 * @return {Roo.BasicDialog} this
30378 sendToBack : function(dlg){
30379 dlg = this.get(dlg);
30380 dlg._lastAccess = -(new Date().getTime());
30386 * Hides all dialogs
30388 hideAll : function(){
30389 for(var id in list){
30390 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
30399 * @class Roo.LayoutDialog
30400 * @extends Roo.BasicDialog
30401 * Dialog which provides adjustments for working with a layout in a Dialog.
30402 * Add your necessary layout config options to the dialog's config.<br>
30403 * Example usage (including a nested layout):
30406 dialog = new Roo.LayoutDialog("download-dlg", {
30415 // layout config merges with the dialog config
30417 tabPosition: "top",
30418 alwaysShowTabs: true
30421 dialog.addKeyListener(27, dialog.hide, dialog);
30422 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
30423 dialog.addButton("Build It!", this.getDownload, this);
30425 // we can even add nested layouts
30426 var innerLayout = new Roo.BorderLayout("dl-inner", {
30436 innerLayout.beginUpdate();
30437 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
30438 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
30439 innerLayout.endUpdate(true);
30441 var layout = dialog.getLayout();
30442 layout.beginUpdate();
30443 layout.add("center", new Roo.ContentPanel("standard-panel",
30444 {title: "Download the Source", fitToFrame:true}));
30445 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
30446 {title: "Build your own roo.js"}));
30447 layout.getRegion("center").showPanel(sp);
30448 layout.endUpdate();
30452 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
30453 * @param {Object} config configuration options
30455 Roo.LayoutDialog = function(el, cfg){
30458 if (typeof(cfg) == 'undefined') {
30459 config = Roo.apply({}, el);
30460 // not sure why we use documentElement here.. - it should always be body.
30461 // IE7 borks horribly if we use documentElement.
30462 // webkit also does not like documentElement - it creates a body element...
30463 el = Roo.get( document.body || document.documentElement ).createChild();
30464 //config.autoCreate = true;
30468 config.autoTabs = false;
30469 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
30470 this.body.setStyle({overflow:"hidden", position:"relative"});
30471 this.layout = new Roo.BorderLayout(this.body.dom, config);
30472 this.layout.monitorWindowResize = false;
30473 this.el.addClass("x-dlg-auto-layout");
30474 // fix case when center region overwrites center function
30475 this.center = Roo.BasicDialog.prototype.center;
30476 this.on("show", this.layout.layout, this.layout, true);
30477 if (config.items) {
30478 var xitems = config.items;
30479 delete config.items;
30480 Roo.each(xitems, this.addxtype, this);
30485 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
30487 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30490 endUpdate : function(){
30491 this.layout.endUpdate();
30495 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30498 beginUpdate : function(){
30499 this.layout.beginUpdate();
30503 * Get the BorderLayout for this dialog
30504 * @return {Roo.BorderLayout}
30506 getLayout : function(){
30507 return this.layout;
30510 showEl : function(){
30511 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30513 this.layout.layout();
30518 // Use the syncHeightBeforeShow config option to control this automatically
30519 syncBodyHeight : function(){
30520 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30521 if(this.layout){this.layout.layout();}
30525 * Add an xtype element (actually adds to the layout.)
30526 * @return {Object} xdata xtype object data.
30529 addxtype : function(c) {
30530 return this.layout.addxtype(c);
30534 * Ext JS Library 1.1.1
30535 * Copyright(c) 2006-2007, Ext JS, LLC.
30537 * Originally Released Under LGPL - original licence link has changed is not relivant.
30540 * <script type="text/javascript">
30544 * @class Roo.MessageBox
30545 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30549 Roo.Msg.alert('Status', 'Changes saved successfully.');
30551 // Prompt for user data:
30552 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30554 // process text value...
30558 // Show a dialog using config options:
30560 title:'Save Changes?',
30561 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30562 buttons: Roo.Msg.YESNOCANCEL,
30569 Roo.MessageBox = function(){
30570 var dlg, opt, mask, waitTimer;
30571 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30572 var buttons, activeTextEl, bwidth;
30575 var handleButton = function(button){
30577 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30581 var handleHide = function(){
30582 if(opt && opt.cls){
30583 dlg.el.removeClass(opt.cls);
30586 Roo.TaskMgr.stop(waitTimer);
30592 var updateButtons = function(b){
30595 buttons["ok"].hide();
30596 buttons["cancel"].hide();
30597 buttons["yes"].hide();
30598 buttons["no"].hide();
30599 dlg.footer.dom.style.display = 'none';
30602 dlg.footer.dom.style.display = '';
30603 for(var k in buttons){
30604 if(typeof buttons[k] != "function"){
30607 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30608 width += buttons[k].el.getWidth()+15;
30618 var handleEsc = function(d, k, e){
30619 if(opt && opt.closable !== false){
30629 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30630 * @return {Roo.BasicDialog} The BasicDialog element
30632 getDialog : function(){
30634 dlg = new Roo.BasicDialog("x-msg-box", {
30639 constraintoviewport:false,
30641 collapsible : false,
30644 width:400, height:100,
30645 buttonAlign:"center",
30646 closeClick : function(){
30647 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30648 handleButton("no");
30650 handleButton("cancel");
30654 dlg.on("hide", handleHide);
30656 dlg.addKeyListener(27, handleEsc);
30658 var bt = this.buttonText;
30659 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30660 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30661 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30662 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30663 bodyEl = dlg.body.createChild({
30665 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>'
30667 msgEl = bodyEl.dom.firstChild;
30668 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30669 textboxEl.enableDisplayMode();
30670 textboxEl.addKeyListener([10,13], function(){
30671 if(dlg.isVisible() && opt && opt.buttons){
30672 if(opt.buttons.ok){
30673 handleButton("ok");
30674 }else if(opt.buttons.yes){
30675 handleButton("yes");
30679 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30680 textareaEl.enableDisplayMode();
30681 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30682 progressEl.enableDisplayMode();
30683 var pf = progressEl.dom.firstChild;
30685 pp = Roo.get(pf.firstChild);
30686 pp.setHeight(pf.offsetHeight);
30694 * Updates the message box body text
30695 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30696 * the XHTML-compliant non-breaking space character '&#160;')
30697 * @return {Roo.MessageBox} This message box
30699 updateText : function(text){
30700 if(!dlg.isVisible() && !opt.width){
30701 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30703 msgEl.innerHTML = text || ' ';
30705 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30706 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30708 Math.min(opt.width || cw , this.maxWidth),
30709 Math.max(opt.minWidth || this.minWidth, bwidth)
30712 activeTextEl.setWidth(w);
30714 if(dlg.isVisible()){
30715 dlg.fixedcenter = false;
30717 // to big, make it scroll. = But as usual stupid IE does not support
30720 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30721 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30722 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30724 bodyEl.dom.style.height = '';
30725 bodyEl.dom.style.overflowY = '';
30728 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30730 bodyEl.dom.style.overflowX = '';
30733 dlg.setContentSize(w, bodyEl.getHeight());
30734 if(dlg.isVisible()){
30735 dlg.fixedcenter = true;
30741 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30742 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30743 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30744 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30745 * @return {Roo.MessageBox} This message box
30747 updateProgress : function(value, text){
30749 this.updateText(text);
30751 if (pp) { // weird bug on my firefox - for some reason this is not defined
30752 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30758 * Returns true if the message box is currently displayed
30759 * @return {Boolean} True if the message box is visible, else false
30761 isVisible : function(){
30762 return dlg && dlg.isVisible();
30766 * Hides the message box if it is displayed
30769 if(this.isVisible()){
30775 * Displays a new message box, or reinitializes an existing message box, based on the config options
30776 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30777 * The following config object properties are supported:
30779 Property Type Description
30780 ---------- --------------- ------------------------------------------------------------------------------------
30781 animEl String/Element An id or Element from which the message box should animate as it opens and
30782 closes (defaults to undefined)
30783 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30784 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30785 closable Boolean False to hide the top-right close button (defaults to true). Note that
30786 progress and wait dialogs will ignore this property and always hide the
30787 close button as they can only be closed programmatically.
30788 cls String A custom CSS class to apply to the message box element
30789 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30790 displayed (defaults to 75)
30791 fn Function A callback function to execute after closing the dialog. The arguments to the
30792 function will be btn (the name of the button that was clicked, if applicable,
30793 e.g. "ok"), and text (the value of the active text field, if applicable).
30794 Progress and wait dialogs will ignore this option since they do not respond to
30795 user actions and can only be closed programmatically, so any required function
30796 should be called by the same code after it closes the dialog.
30797 icon String A CSS class that provides a background image to be used as an icon for
30798 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30799 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30800 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30801 modal Boolean False to allow user interaction with the page while the message box is
30802 displayed (defaults to true)
30803 msg String A string that will replace the existing message box body text (defaults
30804 to the XHTML-compliant non-breaking space character ' ')
30805 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30806 progress Boolean True to display a progress bar (defaults to false)
30807 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30808 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30809 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30810 title String The title text
30811 value String The string value to set into the active textbox element if displayed
30812 wait Boolean True to display a progress bar (defaults to false)
30813 width Number The width of the dialog in pixels
30820 msg: 'Please enter your address:',
30822 buttons: Roo.MessageBox.OKCANCEL,
30825 animEl: 'addAddressBtn'
30828 * @param {Object} config Configuration options
30829 * @return {Roo.MessageBox} This message box
30831 show : function(options)
30834 // this causes nightmares if you show one dialog after another
30835 // especially on callbacks..
30837 if(this.isVisible()){
30840 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30841 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30842 Roo.log("New Dialog Message:" + options.msg )
30843 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30844 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30847 var d = this.getDialog();
30849 d.setTitle(opt.title || " ");
30850 d.close.setDisplayed(opt.closable !== false);
30851 activeTextEl = textboxEl;
30852 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30857 textareaEl.setHeight(typeof opt.multiline == "number" ?
30858 opt.multiline : this.defaultTextHeight);
30859 activeTextEl = textareaEl;
30868 progressEl.setDisplayed(opt.progress === true);
30869 this.updateProgress(0);
30870 activeTextEl.dom.value = opt.value || "";
30872 dlg.setDefaultButton(activeTextEl);
30874 var bs = opt.buttons;
30877 db = buttons["ok"];
30878 }else if(bs && bs.yes){
30879 db = buttons["yes"];
30881 dlg.setDefaultButton(db);
30883 bwidth = updateButtons(opt.buttons);
30884 this.updateText(opt.msg);
30886 d.el.addClass(opt.cls);
30888 d.proxyDrag = opt.proxyDrag === true;
30889 d.modal = opt.modal !== false;
30890 d.mask = opt.modal !== false ? mask : false;
30891 if(!d.isVisible()){
30892 // force it to the end of the z-index stack so it gets a cursor in FF
30893 document.body.appendChild(dlg.el.dom);
30894 d.animateTarget = null;
30895 d.show(options.animEl);
30901 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30902 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30903 * and closing the message box when the process is complete.
30904 * @param {String} title The title bar text
30905 * @param {String} msg The message box body text
30906 * @return {Roo.MessageBox} This message box
30908 progress : function(title, msg){
30915 minWidth: this.minProgressWidth,
30922 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30923 * If a callback function is passed it will be called after the user clicks the button, and the
30924 * id of the button that was clicked will be passed as the only parameter to the callback
30925 * (could also be the top-right close button).
30926 * @param {String} title The title bar text
30927 * @param {String} msg The message box body text
30928 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30929 * @param {Object} scope (optional) The scope of the callback function
30930 * @return {Roo.MessageBox} This message box
30932 alert : function(title, msg, fn, scope){
30945 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30946 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30947 * You are responsible for closing the message box when the process is complete.
30948 * @param {String} msg The message box body text
30949 * @param {String} title (optional) The title bar text
30950 * @return {Roo.MessageBox} This message box
30952 wait : function(msg, title){
30963 waitTimer = Roo.TaskMgr.start({
30965 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30973 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30974 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30975 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30976 * @param {String} title The title bar text
30977 * @param {String} msg The message box body text
30978 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30979 * @param {Object} scope (optional) The scope of the callback function
30980 * @return {Roo.MessageBox} This message box
30982 confirm : function(title, msg, fn, scope){
30986 buttons: this.YESNO,
30995 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30996 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30997 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30998 * (could also be the top-right close button) and the text that was entered will be passed as the two
30999 * parameters to the callback.
31000 * @param {String} title The title bar text
31001 * @param {String} msg The message box body text
31002 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31003 * @param {Object} scope (optional) The scope of the callback function
31004 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31005 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31006 * @return {Roo.MessageBox} This message box
31008 prompt : function(title, msg, fn, scope, multiline){
31012 buttons: this.OKCANCEL,
31017 multiline: multiline,
31024 * Button config that displays a single OK button
31029 * Button config that displays Yes and No buttons
31032 YESNO : {yes:true, no:true},
31034 * Button config that displays OK and Cancel buttons
31037 OKCANCEL : {ok:true, cancel:true},
31039 * Button config that displays Yes, No and Cancel buttons
31042 YESNOCANCEL : {yes:true, no:true, cancel:true},
31045 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31048 defaultTextHeight : 75,
31050 * The maximum width in pixels of the message box (defaults to 600)
31055 * The minimum width in pixels of the message box (defaults to 100)
31060 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31061 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31064 minProgressWidth : 250,
31066 * An object containing the default button text strings that can be overriden for localized language support.
31067 * Supported properties are: ok, cancel, yes and no.
31068 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31081 * Shorthand for {@link Roo.MessageBox}
31083 Roo.Msg = Roo.MessageBox;/*
31085 * Ext JS Library 1.1.1
31086 * Copyright(c) 2006-2007, Ext JS, LLC.
31088 * Originally Released Under LGPL - original licence link has changed is not relivant.
31091 * <script type="text/javascript">
31094 * @class Roo.QuickTips
31095 * Provides attractive and customizable tooltips for any element.
31098 Roo.QuickTips = function(){
31099 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31100 var ce, bd, xy, dd;
31101 var visible = false, disabled = true, inited = false;
31102 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31104 var onOver = function(e){
31108 var t = e.getTarget();
31109 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31112 if(ce && t == ce.el){
31113 clearTimeout(hideProc);
31116 if(t && tagEls[t.id]){
31117 tagEls[t.id].el = t;
31118 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31121 var ttp, et = Roo.fly(t);
31122 var ns = cfg.namespace;
31123 if(tm.interceptTitles && t.title){
31126 t.removeAttribute("title");
31127 e.preventDefault();
31129 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31132 showProc = show.defer(tm.showDelay, tm, [{
31135 width: et.getAttributeNS(ns, cfg.width),
31136 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31137 title: et.getAttributeNS(ns, cfg.title),
31138 cls: et.getAttributeNS(ns, cfg.cls)
31143 var onOut = function(e){
31144 clearTimeout(showProc);
31145 var t = e.getTarget();
31146 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31147 hideProc = setTimeout(hide, tm.hideDelay);
31151 var onMove = function(e){
31157 if(tm.trackMouse && ce){
31162 var onDown = function(e){
31163 clearTimeout(showProc);
31164 clearTimeout(hideProc);
31166 if(tm.hideOnClick){
31169 tm.enable.defer(100, tm);
31174 var getPad = function(){
31175 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31178 var show = function(o){
31182 clearTimeout(dismissProc);
31184 if(removeCls){ // in case manually hidden
31185 el.removeClass(removeCls);
31189 el.addClass(ce.cls);
31190 removeCls = ce.cls;
31193 tipTitle.update(ce.title);
31196 tipTitle.update('');
31199 el.dom.style.width = tm.maxWidth+'px';
31200 //tipBody.dom.style.width = '';
31201 tipBodyText.update(o.text);
31202 var p = getPad(), w = ce.width;
31204 var td = tipBodyText.dom;
31205 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31206 if(aw > tm.maxWidth){
31208 }else if(aw < tm.minWidth){
31214 //tipBody.setWidth(w);
31215 el.setWidth(parseInt(w, 10) + p);
31216 if(ce.autoHide === false){
31217 close.setDisplayed(true);
31222 close.setDisplayed(false);
31228 el.avoidY = xy[1]-18;
31233 el.setStyle("visibility", "visible");
31234 el.fadeIn({callback: afterShow});
31240 var afterShow = function(){
31244 if(tm.autoDismiss && ce.autoHide !== false){
31245 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31250 var hide = function(noanim){
31251 clearTimeout(dismissProc);
31252 clearTimeout(hideProc);
31254 if(el.isVisible()){
31256 if(noanim !== true && tm.animate){
31257 el.fadeOut({callback: afterHide});
31264 var afterHide = function(){
31267 el.removeClass(removeCls);
31274 * @cfg {Number} minWidth
31275 * The minimum width of the quick tip (defaults to 40)
31279 * @cfg {Number} maxWidth
31280 * The maximum width of the quick tip (defaults to 300)
31284 * @cfg {Boolean} interceptTitles
31285 * True to automatically use the element's DOM title value if available (defaults to false)
31287 interceptTitles : false,
31289 * @cfg {Boolean} trackMouse
31290 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31292 trackMouse : false,
31294 * @cfg {Boolean} hideOnClick
31295 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31297 hideOnClick : true,
31299 * @cfg {Number} showDelay
31300 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31304 * @cfg {Number} hideDelay
31305 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31309 * @cfg {Boolean} autoHide
31310 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31311 * Used in conjunction with hideDelay.
31316 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31317 * (defaults to true). Used in conjunction with autoDismissDelay.
31319 autoDismiss : true,
31322 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31324 autoDismissDelay : 5000,
31326 * @cfg {Boolean} animate
31327 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31332 * @cfg {String} title
31333 * Title text to display (defaults to ''). This can be any valid HTML markup.
31337 * @cfg {String} text
31338 * Body text to display (defaults to ''). This can be any valid HTML markup.
31342 * @cfg {String} cls
31343 * A CSS class to apply to the base quick tip element (defaults to '').
31347 * @cfg {Number} width
31348 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31349 * minWidth or maxWidth.
31354 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31355 * or display QuickTips in a page.
31358 tm = Roo.QuickTips;
31359 cfg = tm.tagConfig;
31361 if(!Roo.isReady){ // allow calling of init() before onReady
31362 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
31365 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
31366 el.fxDefaults = {stopFx: true};
31367 // maximum custom styling
31368 //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>');
31369 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>');
31370 tipTitle = el.child('h3');
31371 tipTitle.enableDisplayMode("block");
31372 tipBody = el.child('div.x-tip-bd');
31373 tipBodyText = el.child('div.x-tip-bd-inner');
31374 //bdLeft = el.child('div.x-tip-bd-left');
31375 //bdRight = el.child('div.x-tip-bd-right');
31376 close = el.child('div.x-tip-close');
31377 close.enableDisplayMode("block");
31378 close.on("click", hide);
31379 var d = Roo.get(document);
31380 d.on("mousedown", onDown);
31381 d.on("mouseover", onOver);
31382 d.on("mouseout", onOut);
31383 d.on("mousemove", onMove);
31384 esc = d.addKeyListener(27, hide);
31387 dd = el.initDD("default", null, {
31388 onDrag : function(){
31392 dd.setHandleElId(tipTitle.id);
31401 * Configures a new quick tip instance and assigns it to a target element. The following config options
31404 Property Type Description
31405 ---------- --------------------- ------------------------------------------------------------------------
31406 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
31408 * @param {Object} config The config object
31410 register : function(config){
31411 var cs = config instanceof Array ? config : arguments;
31412 for(var i = 0, len = cs.length; i < len; i++) {
31414 var target = c.target;
31416 if(target instanceof Array){
31417 for(var j = 0, jlen = target.length; j < jlen; j++){
31418 tagEls[target[j]] = c;
31421 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
31428 * Removes this quick tip from its element and destroys it.
31429 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
31431 unregister : function(el){
31432 delete tagEls[Roo.id(el)];
31436 * Enable this quick tip.
31438 enable : function(){
31439 if(inited && disabled){
31441 if(locks.length < 1){
31448 * Disable this quick tip.
31450 disable : function(){
31452 clearTimeout(showProc);
31453 clearTimeout(hideProc);
31454 clearTimeout(dismissProc);
31462 * Returns true if the quick tip is enabled, else false.
31464 isEnabled : function(){
31471 attribute : "qtip",
31481 // backwards compat
31482 Roo.QuickTips.tips = Roo.QuickTips.register;/*
31484 * Ext JS Library 1.1.1
31485 * Copyright(c) 2006-2007, Ext JS, LLC.
31487 * Originally Released Under LGPL - original licence link has changed is not relivant.
31490 * <script type="text/javascript">
31495 * @class Roo.tree.TreePanel
31496 * @extends Roo.data.Tree
31498 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31499 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31500 * @cfg {Boolean} enableDD true to enable drag and drop
31501 * @cfg {Boolean} enableDrag true to enable just drag
31502 * @cfg {Boolean} enableDrop true to enable just drop
31503 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31504 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31505 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31506 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31507 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31508 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31509 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31510 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31511 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31512 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31513 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31514 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31515 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31516 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31517 * @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>
31518 * @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>
31521 * @param {String/HTMLElement/Element} el The container element
31522 * @param {Object} config
31524 Roo.tree.TreePanel = function(el, config){
31526 var loader = false;
31528 root = config.root;
31529 delete config.root;
31531 if (config.loader) {
31532 loader = config.loader;
31533 delete config.loader;
31536 Roo.apply(this, config);
31537 Roo.tree.TreePanel.superclass.constructor.call(this);
31538 this.el = Roo.get(el);
31539 this.el.addClass('x-tree');
31540 //console.log(root);
31542 this.setRootNode( Roo.factory(root, Roo.tree));
31545 this.loader = Roo.factory(loader, Roo.tree);
31548 * Read-only. The id of the container element becomes this TreePanel's id.
31550 this.id = this.el.id;
31553 * @event beforeload
31554 * Fires before a node is loaded, return false to cancel
31555 * @param {Node} node The node being loaded
31557 "beforeload" : true,
31560 * Fires when a node is loaded
31561 * @param {Node} node The node that was loaded
31565 * @event textchange
31566 * Fires when the text for a node is changed
31567 * @param {Node} node The node
31568 * @param {String} text The new text
31569 * @param {String} oldText The old text
31571 "textchange" : true,
31573 * @event beforeexpand
31574 * Fires before a node is expanded, return false to cancel.
31575 * @param {Node} node The node
31576 * @param {Boolean} deep
31577 * @param {Boolean} anim
31579 "beforeexpand" : true,
31581 * @event beforecollapse
31582 * Fires before a node is collapsed, return false to cancel.
31583 * @param {Node} node The node
31584 * @param {Boolean} deep
31585 * @param {Boolean} anim
31587 "beforecollapse" : true,
31590 * Fires when a node is expanded
31591 * @param {Node} node The node
31595 * @event disabledchange
31596 * Fires when the disabled status of a node changes
31597 * @param {Node} node The node
31598 * @param {Boolean} disabled
31600 "disabledchange" : true,
31603 * Fires when a node is collapsed
31604 * @param {Node} node The node
31608 * @event beforeclick
31609 * Fires before click processing on a node. Return false to cancel the default action.
31610 * @param {Node} node The node
31611 * @param {Roo.EventObject} e The event object
31613 "beforeclick":true,
31615 * @event checkchange
31616 * Fires when a node with a checkbox's checked property changes
31617 * @param {Node} this This node
31618 * @param {Boolean} checked
31620 "checkchange":true,
31623 * Fires when a node is clicked
31624 * @param {Node} node The node
31625 * @param {Roo.EventObject} e The event object
31630 * Fires when a node is double clicked
31631 * @param {Node} node The node
31632 * @param {Roo.EventObject} e The event object
31636 * @event contextmenu
31637 * Fires when a node is right clicked
31638 * @param {Node} node The node
31639 * @param {Roo.EventObject} e The event object
31641 "contextmenu":true,
31643 * @event beforechildrenrendered
31644 * Fires right before the child nodes for a node are rendered
31645 * @param {Node} node The node
31647 "beforechildrenrendered":true,
31650 * Fires when a node starts being dragged
31651 * @param {Roo.tree.TreePanel} this
31652 * @param {Roo.tree.TreeNode} node
31653 * @param {event} e The raw browser event
31655 "startdrag" : true,
31658 * Fires when a drag operation is complete
31659 * @param {Roo.tree.TreePanel} this
31660 * @param {Roo.tree.TreeNode} node
31661 * @param {event} e The raw browser event
31666 * Fires when a dragged node is dropped on a valid DD target
31667 * @param {Roo.tree.TreePanel} this
31668 * @param {Roo.tree.TreeNode} node
31669 * @param {DD} dd The dd it was dropped on
31670 * @param {event} e The raw browser event
31674 * @event beforenodedrop
31675 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31676 * passed to handlers has the following properties:<br />
31677 * <ul style="padding:5px;padding-left:16px;">
31678 * <li>tree - The TreePanel</li>
31679 * <li>target - The node being targeted for the drop</li>
31680 * <li>data - The drag data from the drag source</li>
31681 * <li>point - The point of the drop - append, above or below</li>
31682 * <li>source - The drag source</li>
31683 * <li>rawEvent - Raw mouse event</li>
31684 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31685 * to be inserted by setting them on this object.</li>
31686 * <li>cancel - Set this to true to cancel the drop.</li>
31688 * @param {Object} dropEvent
31690 "beforenodedrop" : true,
31693 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31694 * passed to handlers has the following properties:<br />
31695 * <ul style="padding:5px;padding-left:16px;">
31696 * <li>tree - The TreePanel</li>
31697 * <li>target - The node being targeted for the drop</li>
31698 * <li>data - The drag data from the drag source</li>
31699 * <li>point - The point of the drop - append, above or below</li>
31700 * <li>source - The drag source</li>
31701 * <li>rawEvent - Raw mouse event</li>
31702 * <li>dropNode - Dropped node(s).</li>
31704 * @param {Object} dropEvent
31708 * @event nodedragover
31709 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31710 * passed to handlers has the following properties:<br />
31711 * <ul style="padding:5px;padding-left:16px;">
31712 * <li>tree - The TreePanel</li>
31713 * <li>target - The node being targeted for the drop</li>
31714 * <li>data - The drag data from the drag source</li>
31715 * <li>point - The point of the drop - append, above or below</li>
31716 * <li>source - The drag source</li>
31717 * <li>rawEvent - Raw mouse event</li>
31718 * <li>dropNode - Drop node(s) provided by the source.</li>
31719 * <li>cancel - Set this to true to signal drop not allowed.</li>
31721 * @param {Object} dragOverEvent
31723 "nodedragover" : true
31726 if(this.singleExpand){
31727 this.on("beforeexpand", this.restrictExpand, this);
31730 this.editor.tree = this;
31731 this.editor = Roo.factory(this.editor, Roo.tree);
31734 if (this.selModel) {
31735 this.selModel = Roo.factory(this.selModel, Roo.tree);
31739 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31740 rootVisible : true,
31741 animate: Roo.enableFx,
31744 hlDrop : Roo.enableFx,
31748 rendererTip: false,
31750 restrictExpand : function(node){
31751 var p = node.parentNode;
31753 if(p.expandedChild && p.expandedChild.parentNode == p){
31754 p.expandedChild.collapse();
31756 p.expandedChild = node;
31760 // private override
31761 setRootNode : function(node){
31762 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31763 if(!this.rootVisible){
31764 node.ui = new Roo.tree.RootTreeNodeUI(node);
31770 * Returns the container element for this TreePanel
31772 getEl : function(){
31777 * Returns the default TreeLoader for this TreePanel
31779 getLoader : function(){
31780 return this.loader;
31786 expandAll : function(){
31787 this.root.expand(true);
31791 * Collapse all nodes
31793 collapseAll : function(){
31794 this.root.collapse(true);
31798 * Returns the selection model used by this TreePanel
31800 getSelectionModel : function(){
31801 if(!this.selModel){
31802 this.selModel = new Roo.tree.DefaultSelectionModel();
31804 return this.selModel;
31808 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31809 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31810 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31813 getChecked : function(a, startNode){
31814 startNode = startNode || this.root;
31816 var f = function(){
31817 if(this.attributes.checked){
31818 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31821 startNode.cascade(f);
31826 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31827 * @param {String} path
31828 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31829 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31830 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31832 expandPath : function(path, attr, callback){
31833 attr = attr || "id";
31834 var keys = path.split(this.pathSeparator);
31835 var curNode = this.root;
31836 if(curNode.attributes[attr] != keys[1]){ // invalid root
31838 callback(false, null);
31843 var f = function(){
31844 if(++index == keys.length){
31846 callback(true, curNode);
31850 var c = curNode.findChild(attr, keys[index]);
31853 callback(false, curNode);
31858 c.expand(false, false, f);
31860 curNode.expand(false, false, f);
31864 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31865 * @param {String} path
31866 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31867 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31868 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31870 selectPath : function(path, attr, callback){
31871 attr = attr || "id";
31872 var keys = path.split(this.pathSeparator);
31873 var v = keys.pop();
31874 if(keys.length > 0){
31875 var f = function(success, node){
31876 if(success && node){
31877 var n = node.findChild(attr, v);
31883 }else if(callback){
31884 callback(false, n);
31888 callback(false, n);
31892 this.expandPath(keys.join(this.pathSeparator), attr, f);
31894 this.root.select();
31896 callback(true, this.root);
31901 getTreeEl : function(){
31906 * Trigger rendering of this TreePanel
31908 render : function(){
31909 if (this.innerCt) {
31910 return this; // stop it rendering more than once!!
31913 this.innerCt = this.el.createChild({tag:"ul",
31914 cls:"x-tree-root-ct " +
31915 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31917 if(this.containerScroll){
31918 Roo.dd.ScrollManager.register(this.el);
31920 if((this.enableDD || this.enableDrop) && !this.dropZone){
31922 * The dropZone used by this tree if drop is enabled
31923 * @type Roo.tree.TreeDropZone
31925 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31926 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31929 if((this.enableDD || this.enableDrag) && !this.dragZone){
31931 * The dragZone used by this tree if drag is enabled
31932 * @type Roo.tree.TreeDragZone
31934 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31935 ddGroup: this.ddGroup || "TreeDD",
31936 scroll: this.ddScroll
31939 this.getSelectionModel().init(this);
31941 Roo.log("ROOT not set in tree");
31944 this.root.render();
31945 if(!this.rootVisible){
31946 this.root.renderChildren();
31952 * Ext JS Library 1.1.1
31953 * Copyright(c) 2006-2007, Ext JS, LLC.
31955 * Originally Released Under LGPL - original licence link has changed is not relivant.
31958 * <script type="text/javascript">
31963 * @class Roo.tree.DefaultSelectionModel
31964 * @extends Roo.util.Observable
31965 * The default single selection for a TreePanel.
31966 * @param {Object} cfg Configuration
31968 Roo.tree.DefaultSelectionModel = function(cfg){
31969 this.selNode = null;
31975 * @event selectionchange
31976 * Fires when the selected node changes
31977 * @param {DefaultSelectionModel} this
31978 * @param {TreeNode} node the new selection
31980 "selectionchange" : true,
31983 * @event beforeselect
31984 * Fires before the selected node changes, return false to cancel the change
31985 * @param {DefaultSelectionModel} this
31986 * @param {TreeNode} node the new selection
31987 * @param {TreeNode} node the old selection
31989 "beforeselect" : true
31992 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31995 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31996 init : function(tree){
31998 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31999 tree.on("click", this.onNodeClick, this);
32002 onNodeClick : function(node, e){
32003 if (e.ctrlKey && this.selNode == node) {
32004 this.unselect(node);
32012 * @param {TreeNode} node The node to select
32013 * @return {TreeNode} The selected node
32015 select : function(node){
32016 var last = this.selNode;
32017 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32019 last.ui.onSelectedChange(false);
32021 this.selNode = node;
32022 node.ui.onSelectedChange(true);
32023 this.fireEvent("selectionchange", this, node, last);
32030 * @param {TreeNode} node The node to unselect
32032 unselect : function(node){
32033 if(this.selNode == node){
32034 this.clearSelections();
32039 * Clear all selections
32041 clearSelections : function(){
32042 var n = this.selNode;
32044 n.ui.onSelectedChange(false);
32045 this.selNode = null;
32046 this.fireEvent("selectionchange", this, null);
32052 * Get the selected node
32053 * @return {TreeNode} The selected node
32055 getSelectedNode : function(){
32056 return this.selNode;
32060 * Returns true if the node is selected
32061 * @param {TreeNode} node The node to check
32062 * @return {Boolean}
32064 isSelected : function(node){
32065 return this.selNode == node;
32069 * Selects the node above the selected node in the tree, intelligently walking the nodes
32070 * @return TreeNode The new selection
32072 selectPrevious : function(){
32073 var s = this.selNode || this.lastSelNode;
32077 var ps = s.previousSibling;
32079 if(!ps.isExpanded() || ps.childNodes.length < 1){
32080 return this.select(ps);
32082 var lc = ps.lastChild;
32083 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32086 return this.select(lc);
32088 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32089 return this.select(s.parentNode);
32095 * Selects the node above the selected node in the tree, intelligently walking the nodes
32096 * @return TreeNode The new selection
32098 selectNext : function(){
32099 var s = this.selNode || this.lastSelNode;
32103 if(s.firstChild && s.isExpanded()){
32104 return this.select(s.firstChild);
32105 }else if(s.nextSibling){
32106 return this.select(s.nextSibling);
32107 }else if(s.parentNode){
32109 s.parentNode.bubble(function(){
32110 if(this.nextSibling){
32111 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32120 onKeyDown : function(e){
32121 var s = this.selNode || this.lastSelNode;
32122 // undesirable, but required
32127 var k = e.getKey();
32135 this.selectPrevious();
32138 e.preventDefault();
32139 if(s.hasChildNodes()){
32140 if(!s.isExpanded()){
32142 }else if(s.firstChild){
32143 this.select(s.firstChild, e);
32148 e.preventDefault();
32149 if(s.hasChildNodes() && s.isExpanded()){
32151 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32152 this.select(s.parentNode, e);
32160 * @class Roo.tree.MultiSelectionModel
32161 * @extends Roo.util.Observable
32162 * Multi selection for a TreePanel.
32163 * @param {Object} cfg Configuration
32165 Roo.tree.MultiSelectionModel = function(){
32166 this.selNodes = [];
32170 * @event selectionchange
32171 * Fires when the selected nodes change
32172 * @param {MultiSelectionModel} this
32173 * @param {Array} nodes Array of the selected nodes
32175 "selectionchange" : true
32177 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32181 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32182 init : function(tree){
32184 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32185 tree.on("click", this.onNodeClick, this);
32188 onNodeClick : function(node, e){
32189 this.select(node, e, e.ctrlKey);
32194 * @param {TreeNode} node The node to select
32195 * @param {EventObject} e (optional) An event associated with the selection
32196 * @param {Boolean} keepExisting True to retain existing selections
32197 * @return {TreeNode} The selected node
32199 select : function(node, e, keepExisting){
32200 if(keepExisting !== true){
32201 this.clearSelections(true);
32203 if(this.isSelected(node)){
32204 this.lastSelNode = node;
32207 this.selNodes.push(node);
32208 this.selMap[node.id] = node;
32209 this.lastSelNode = node;
32210 node.ui.onSelectedChange(true);
32211 this.fireEvent("selectionchange", this, this.selNodes);
32217 * @param {TreeNode} node The node to unselect
32219 unselect : function(node){
32220 if(this.selMap[node.id]){
32221 node.ui.onSelectedChange(false);
32222 var sn = this.selNodes;
32225 index = sn.indexOf(node);
32227 for(var i = 0, len = sn.length; i < len; i++){
32235 this.selNodes.splice(index, 1);
32237 delete this.selMap[node.id];
32238 this.fireEvent("selectionchange", this, this.selNodes);
32243 * Clear all selections
32245 clearSelections : function(suppressEvent){
32246 var sn = this.selNodes;
32248 for(var i = 0, len = sn.length; i < len; i++){
32249 sn[i].ui.onSelectedChange(false);
32251 this.selNodes = [];
32253 if(suppressEvent !== true){
32254 this.fireEvent("selectionchange", this, this.selNodes);
32260 * Returns true if the node is selected
32261 * @param {TreeNode} node The node to check
32262 * @return {Boolean}
32264 isSelected : function(node){
32265 return this.selMap[node.id] ? true : false;
32269 * Returns an array of the selected nodes
32272 getSelectedNodes : function(){
32273 return this.selNodes;
32276 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32278 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32280 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32283 * Ext JS Library 1.1.1
32284 * Copyright(c) 2006-2007, Ext JS, LLC.
32286 * Originally Released Under LGPL - original licence link has changed is not relivant.
32289 * <script type="text/javascript">
32293 * @class Roo.tree.TreeNode
32294 * @extends Roo.data.Node
32295 * @cfg {String} text The text for this node
32296 * @cfg {Boolean} expanded true to start the node expanded
32297 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32298 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32299 * @cfg {Boolean} disabled true to start the node disabled
32300 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32301 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32302 * @cfg {String} cls A css class to be added to the node
32303 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32304 * @cfg {String} href URL of the link used for the node (defaults to #)
32305 * @cfg {String} hrefTarget target frame for the link
32306 * @cfg {String} qtip An Ext QuickTip for the node
32307 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32308 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32309 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32310 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32311 * (defaults to undefined with no checkbox rendered)
32313 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32315 Roo.tree.TreeNode = function(attributes){
32316 attributes = attributes || {};
32317 if(typeof attributes == "string"){
32318 attributes = {text: attributes};
32320 this.childrenRendered = false;
32321 this.rendered = false;
32322 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32323 this.expanded = attributes.expanded === true;
32324 this.isTarget = attributes.isTarget !== false;
32325 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32326 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32329 * Read-only. The text for this node. To change it use setText().
32332 this.text = attributes.text;
32334 * True if this node is disabled.
32337 this.disabled = attributes.disabled === true;
32341 * @event textchange
32342 * Fires when the text for this node is changed
32343 * @param {Node} this This node
32344 * @param {String} text The new text
32345 * @param {String} oldText The old text
32347 "textchange" : true,
32349 * @event beforeexpand
32350 * Fires before this node is expanded, return false to cancel.
32351 * @param {Node} this This node
32352 * @param {Boolean} deep
32353 * @param {Boolean} anim
32355 "beforeexpand" : true,
32357 * @event beforecollapse
32358 * Fires before this node is collapsed, return false to cancel.
32359 * @param {Node} this This node
32360 * @param {Boolean} deep
32361 * @param {Boolean} anim
32363 "beforecollapse" : true,
32366 * Fires when this node is expanded
32367 * @param {Node} this This node
32371 * @event disabledchange
32372 * Fires when the disabled status of this node changes
32373 * @param {Node} this This node
32374 * @param {Boolean} disabled
32376 "disabledchange" : true,
32379 * Fires when this node is collapsed
32380 * @param {Node} this This node
32384 * @event beforeclick
32385 * Fires before click processing. Return false to cancel the default action.
32386 * @param {Node} this This node
32387 * @param {Roo.EventObject} e The event object
32389 "beforeclick":true,
32391 * @event checkchange
32392 * Fires when a node with a checkbox's checked property changes
32393 * @param {Node} this This node
32394 * @param {Boolean} checked
32396 "checkchange":true,
32399 * Fires when this node is clicked
32400 * @param {Node} this This node
32401 * @param {Roo.EventObject} e The event object
32406 * Fires when this node is double clicked
32407 * @param {Node} this This node
32408 * @param {Roo.EventObject} e The event object
32412 * @event contextmenu
32413 * Fires when this node is right clicked
32414 * @param {Node} this This node
32415 * @param {Roo.EventObject} e The event object
32417 "contextmenu":true,
32419 * @event beforechildrenrendered
32420 * Fires right before the child nodes for this node are rendered
32421 * @param {Node} this This node
32423 "beforechildrenrendered":true
32426 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
32429 * Read-only. The UI for this node
32432 this.ui = new uiClass(this);
32434 // finally support items[]
32435 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
32440 Roo.each(this.attributes.items, function(c) {
32441 this.appendChild(Roo.factory(c,Roo.Tree));
32443 delete this.attributes.items;
32448 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
32449 preventHScroll: true,
32451 * Returns true if this node is expanded
32452 * @return {Boolean}
32454 isExpanded : function(){
32455 return this.expanded;
32459 * Returns the UI object for this node
32460 * @return {TreeNodeUI}
32462 getUI : function(){
32466 // private override
32467 setFirstChild : function(node){
32468 var of = this.firstChild;
32469 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
32470 if(this.childrenRendered && of && node != of){
32471 of.renderIndent(true, true);
32474 this.renderIndent(true, true);
32478 // private override
32479 setLastChild : function(node){
32480 var ol = this.lastChild;
32481 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
32482 if(this.childrenRendered && ol && node != ol){
32483 ol.renderIndent(true, true);
32486 this.renderIndent(true, true);
32490 // these methods are overridden to provide lazy rendering support
32491 // private override
32492 appendChild : function()
32494 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32495 if(node && this.childrenRendered){
32498 this.ui.updateExpandIcon();
32502 // private override
32503 removeChild : function(node){
32504 this.ownerTree.getSelectionModel().unselect(node);
32505 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32506 // if it's been rendered remove dom node
32507 if(this.childrenRendered){
32510 if(this.childNodes.length < 1){
32511 this.collapse(false, false);
32513 this.ui.updateExpandIcon();
32515 if(!this.firstChild) {
32516 this.childrenRendered = false;
32521 // private override
32522 insertBefore : function(node, refNode){
32523 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32524 if(newNode && refNode && this.childrenRendered){
32527 this.ui.updateExpandIcon();
32532 * Sets the text for this node
32533 * @param {String} text
32535 setText : function(text){
32536 var oldText = this.text;
32538 this.attributes.text = text;
32539 if(this.rendered){ // event without subscribing
32540 this.ui.onTextChange(this, text, oldText);
32542 this.fireEvent("textchange", this, text, oldText);
32546 * Triggers selection of this node
32548 select : function(){
32549 this.getOwnerTree().getSelectionModel().select(this);
32553 * Triggers deselection of this node
32555 unselect : function(){
32556 this.getOwnerTree().getSelectionModel().unselect(this);
32560 * Returns true if this node is selected
32561 * @return {Boolean}
32563 isSelected : function(){
32564 return this.getOwnerTree().getSelectionModel().isSelected(this);
32568 * Expand this node.
32569 * @param {Boolean} deep (optional) True to expand all children as well
32570 * @param {Boolean} anim (optional) false to cancel the default animation
32571 * @param {Function} callback (optional) A callback to be called when
32572 * expanding this node completes (does not wait for deep expand to complete).
32573 * Called with 1 parameter, this node.
32575 expand : function(deep, anim, callback){
32576 if(!this.expanded){
32577 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32580 if(!this.childrenRendered){
32581 this.renderChildren();
32583 this.expanded = true;
32584 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32585 this.ui.animExpand(function(){
32586 this.fireEvent("expand", this);
32587 if(typeof callback == "function"){
32591 this.expandChildNodes(true);
32593 }.createDelegate(this));
32597 this.fireEvent("expand", this);
32598 if(typeof callback == "function"){
32603 if(typeof callback == "function"){
32608 this.expandChildNodes(true);
32612 isHiddenRoot : function(){
32613 return this.isRoot && !this.getOwnerTree().rootVisible;
32617 * Collapse this node.
32618 * @param {Boolean} deep (optional) True to collapse all children as well
32619 * @param {Boolean} anim (optional) false to cancel the default animation
32621 collapse : function(deep, anim){
32622 if(this.expanded && !this.isHiddenRoot()){
32623 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32626 this.expanded = false;
32627 if((this.getOwnerTree().animate && anim !== false) || anim){
32628 this.ui.animCollapse(function(){
32629 this.fireEvent("collapse", this);
32631 this.collapseChildNodes(true);
32633 }.createDelegate(this));
32636 this.ui.collapse();
32637 this.fireEvent("collapse", this);
32641 var cs = this.childNodes;
32642 for(var i = 0, len = cs.length; i < len; i++) {
32643 cs[i].collapse(true, false);
32649 delayedExpand : function(delay){
32650 if(!this.expandProcId){
32651 this.expandProcId = this.expand.defer(delay, this);
32656 cancelExpand : function(){
32657 if(this.expandProcId){
32658 clearTimeout(this.expandProcId);
32660 this.expandProcId = false;
32664 * Toggles expanded/collapsed state of the node
32666 toggle : function(){
32675 * Ensures all parent nodes are expanded
32677 ensureVisible : function(callback){
32678 var tree = this.getOwnerTree();
32679 tree.expandPath(this.parentNode.getPath(), false, function(){
32680 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32681 Roo.callback(callback);
32682 }.createDelegate(this));
32686 * Expand all child nodes
32687 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32689 expandChildNodes : function(deep){
32690 var cs = this.childNodes;
32691 for(var i = 0, len = cs.length; i < len; i++) {
32692 cs[i].expand(deep);
32697 * Collapse all child nodes
32698 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32700 collapseChildNodes : function(deep){
32701 var cs = this.childNodes;
32702 for(var i = 0, len = cs.length; i < len; i++) {
32703 cs[i].collapse(deep);
32708 * Disables this node
32710 disable : function(){
32711 this.disabled = true;
32713 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32714 this.ui.onDisableChange(this, true);
32716 this.fireEvent("disabledchange", this, true);
32720 * Enables this node
32722 enable : function(){
32723 this.disabled = false;
32724 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32725 this.ui.onDisableChange(this, false);
32727 this.fireEvent("disabledchange", this, false);
32731 renderChildren : function(suppressEvent){
32732 if(suppressEvent !== false){
32733 this.fireEvent("beforechildrenrendered", this);
32735 var cs = this.childNodes;
32736 for(var i = 0, len = cs.length; i < len; i++){
32737 cs[i].render(true);
32739 this.childrenRendered = true;
32743 sort : function(fn, scope){
32744 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32745 if(this.childrenRendered){
32746 var cs = this.childNodes;
32747 for(var i = 0, len = cs.length; i < len; i++){
32748 cs[i].render(true);
32754 render : function(bulkRender){
32755 this.ui.render(bulkRender);
32756 if(!this.rendered){
32757 this.rendered = true;
32759 this.expanded = false;
32760 this.expand(false, false);
32766 renderIndent : function(deep, refresh){
32768 this.ui.childIndent = null;
32770 this.ui.renderIndent();
32771 if(deep === true && this.childrenRendered){
32772 var cs = this.childNodes;
32773 for(var i = 0, len = cs.length; i < len; i++){
32774 cs[i].renderIndent(true, refresh);
32780 * Ext JS Library 1.1.1
32781 * Copyright(c) 2006-2007, Ext JS, LLC.
32783 * Originally Released Under LGPL - original licence link has changed is not relivant.
32786 * <script type="text/javascript">
32790 * @class Roo.tree.AsyncTreeNode
32791 * @extends Roo.tree.TreeNode
32792 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32794 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32796 Roo.tree.AsyncTreeNode = function(config){
32797 this.loaded = false;
32798 this.loading = false;
32799 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32801 * @event beforeload
32802 * Fires before this node is loaded, return false to cancel
32803 * @param {Node} this This node
32805 this.addEvents({'beforeload':true, 'load': true});
32808 * Fires when this node is loaded
32809 * @param {Node} this This node
32812 * The loader used by this node (defaults to using the tree's defined loader)
32817 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32818 expand : function(deep, anim, callback){
32819 if(this.loading){ // if an async load is already running, waiting til it's done
32821 var f = function(){
32822 if(!this.loading){ // done loading
32823 clearInterval(timer);
32824 this.expand(deep, anim, callback);
32826 }.createDelegate(this);
32827 timer = setInterval(f, 200);
32831 if(this.fireEvent("beforeload", this) === false){
32834 this.loading = true;
32835 this.ui.beforeLoad(this);
32836 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32838 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32842 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32846 * Returns true if this node is currently loading
32847 * @return {Boolean}
32849 isLoading : function(){
32850 return this.loading;
32853 loadComplete : function(deep, anim, callback){
32854 this.loading = false;
32855 this.loaded = true;
32856 this.ui.afterLoad(this);
32857 this.fireEvent("load", this);
32858 this.expand(deep, anim, callback);
32862 * Returns true if this node has been loaded
32863 * @return {Boolean}
32865 isLoaded : function(){
32866 return this.loaded;
32869 hasChildNodes : function(){
32870 if(!this.isLeaf() && !this.loaded){
32873 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32878 * Trigger a reload for this node
32879 * @param {Function} callback
32881 reload : function(callback){
32882 this.collapse(false, false);
32883 while(this.firstChild){
32884 this.removeChild(this.firstChild);
32886 this.childrenRendered = false;
32887 this.loaded = false;
32888 if(this.isHiddenRoot()){
32889 this.expanded = false;
32891 this.expand(false, false, callback);
32895 * Ext JS Library 1.1.1
32896 * Copyright(c) 2006-2007, Ext JS, LLC.
32898 * Originally Released Under LGPL - original licence link has changed is not relivant.
32901 * <script type="text/javascript">
32905 * @class Roo.tree.TreeNodeUI
32907 * @param {Object} node The node to render
32908 * The TreeNode UI implementation is separate from the
32909 * tree implementation. Unless you are customizing the tree UI,
32910 * you should never have to use this directly.
32912 Roo.tree.TreeNodeUI = function(node){
32914 this.rendered = false;
32915 this.animating = false;
32916 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32919 Roo.tree.TreeNodeUI.prototype = {
32920 removeChild : function(node){
32922 this.ctNode.removeChild(node.ui.getEl());
32926 beforeLoad : function(){
32927 this.addClass("x-tree-node-loading");
32930 afterLoad : function(){
32931 this.removeClass("x-tree-node-loading");
32934 onTextChange : function(node, text, oldText){
32936 this.textNode.innerHTML = text;
32940 onDisableChange : function(node, state){
32941 this.disabled = state;
32943 this.addClass("x-tree-node-disabled");
32945 this.removeClass("x-tree-node-disabled");
32949 onSelectedChange : function(state){
32952 this.addClass("x-tree-selected");
32955 this.removeClass("x-tree-selected");
32959 onMove : function(tree, node, oldParent, newParent, index, refNode){
32960 this.childIndent = null;
32962 var targetNode = newParent.ui.getContainer();
32963 if(!targetNode){//target not rendered
32964 this.holder = document.createElement("div");
32965 this.holder.appendChild(this.wrap);
32968 var insertBefore = refNode ? refNode.ui.getEl() : null;
32970 targetNode.insertBefore(this.wrap, insertBefore);
32972 targetNode.appendChild(this.wrap);
32974 this.node.renderIndent(true);
32978 addClass : function(cls){
32980 Roo.fly(this.elNode).addClass(cls);
32984 removeClass : function(cls){
32986 Roo.fly(this.elNode).removeClass(cls);
32990 remove : function(){
32992 this.holder = document.createElement("div");
32993 this.holder.appendChild(this.wrap);
32997 fireEvent : function(){
32998 return this.node.fireEvent.apply(this.node, arguments);
33001 initEvents : function(){
33002 this.node.on("move", this.onMove, this);
33003 var E = Roo.EventManager;
33004 var a = this.anchor;
33006 var el = Roo.fly(a, '_treeui');
33008 if(Roo.isOpera){ // opera render bug ignores the CSS
33009 el.setStyle("text-decoration", "none");
33012 el.on("click", this.onClick, this);
33013 el.on("dblclick", this.onDblClick, this);
33016 Roo.EventManager.on(this.checkbox,
33017 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33020 el.on("contextmenu", this.onContextMenu, this);
33022 var icon = Roo.fly(this.iconNode);
33023 icon.on("click", this.onClick, this);
33024 icon.on("dblclick", this.onDblClick, this);
33025 icon.on("contextmenu", this.onContextMenu, this);
33026 E.on(this.ecNode, "click", this.ecClick, this, true);
33028 if(this.node.disabled){
33029 this.addClass("x-tree-node-disabled");
33031 if(this.node.hidden){
33032 this.addClass("x-tree-node-disabled");
33034 var ot = this.node.getOwnerTree();
33035 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33036 if(dd && (!this.node.isRoot || ot.rootVisible)){
33037 Roo.dd.Registry.register(this.elNode, {
33039 handles: this.getDDHandles(),
33045 getDDHandles : function(){
33046 return [this.iconNode, this.textNode];
33051 this.wrap.style.display = "none";
33057 this.wrap.style.display = "";
33061 onContextMenu : function(e){
33062 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33063 e.preventDefault();
33065 this.fireEvent("contextmenu", this.node, e);
33069 onClick : function(e){
33074 if(this.fireEvent("beforeclick", this.node, e) !== false){
33075 if(!this.disabled && this.node.attributes.href){
33076 this.fireEvent("click", this.node, e);
33079 e.preventDefault();
33084 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33085 this.node.toggle();
33088 this.fireEvent("click", this.node, e);
33094 onDblClick : function(e){
33095 e.preventDefault();
33100 this.toggleCheck();
33102 if(!this.animating && this.node.hasChildNodes()){
33103 this.node.toggle();
33105 this.fireEvent("dblclick", this.node, e);
33108 onCheckChange : function(){
33109 var checked = this.checkbox.checked;
33110 this.node.attributes.checked = checked;
33111 this.fireEvent('checkchange', this.node, checked);
33114 ecClick : function(e){
33115 if(!this.animating && this.node.hasChildNodes()){
33116 this.node.toggle();
33120 startDrop : function(){
33121 this.dropping = true;
33124 // delayed drop so the click event doesn't get fired on a drop
33125 endDrop : function(){
33126 setTimeout(function(){
33127 this.dropping = false;
33128 }.createDelegate(this), 50);
33131 expand : function(){
33132 this.updateExpandIcon();
33133 this.ctNode.style.display = "";
33136 focus : function(){
33137 if(!this.node.preventHScroll){
33138 try{this.anchor.focus();
33140 }else if(!Roo.isIE){
33142 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33143 var l = noscroll.scrollLeft;
33144 this.anchor.focus();
33145 noscroll.scrollLeft = l;
33150 toggleCheck : function(value){
33151 var cb = this.checkbox;
33153 cb.checked = (value === undefined ? !cb.checked : value);
33159 this.anchor.blur();
33163 animExpand : function(callback){
33164 var ct = Roo.get(this.ctNode);
33166 if(!this.node.hasChildNodes()){
33167 this.updateExpandIcon();
33168 this.ctNode.style.display = "";
33169 Roo.callback(callback);
33172 this.animating = true;
33173 this.updateExpandIcon();
33176 callback : function(){
33177 this.animating = false;
33178 Roo.callback(callback);
33181 duration: this.node.ownerTree.duration || .25
33185 highlight : function(){
33186 var tree = this.node.getOwnerTree();
33187 Roo.fly(this.wrap).highlight(
33188 tree.hlColor || "C3DAF9",
33189 {endColor: tree.hlBaseColor}
33193 collapse : function(){
33194 this.updateExpandIcon();
33195 this.ctNode.style.display = "none";
33198 animCollapse : function(callback){
33199 var ct = Roo.get(this.ctNode);
33200 ct.enableDisplayMode('block');
33203 this.animating = true;
33204 this.updateExpandIcon();
33207 callback : function(){
33208 this.animating = false;
33209 Roo.callback(callback);
33212 duration: this.node.ownerTree.duration || .25
33216 getContainer : function(){
33217 return this.ctNode;
33220 getEl : function(){
33224 appendDDGhost : function(ghostNode){
33225 ghostNode.appendChild(this.elNode.cloneNode(true));
33228 getDDRepairXY : function(){
33229 return Roo.lib.Dom.getXY(this.iconNode);
33232 onRender : function(){
33236 render : function(bulkRender){
33237 var n = this.node, a = n.attributes;
33238 var targetNode = n.parentNode ?
33239 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33241 if(!this.rendered){
33242 this.rendered = true;
33244 this.renderElements(n, a, targetNode, bulkRender);
33247 if(this.textNode.setAttributeNS){
33248 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33250 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33253 this.textNode.setAttribute("ext:qtip", a.qtip);
33255 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33258 }else if(a.qtipCfg){
33259 a.qtipCfg.target = Roo.id(this.textNode);
33260 Roo.QuickTips.register(a.qtipCfg);
33263 if(!this.node.expanded){
33264 this.updateExpandIcon();
33267 if(bulkRender === true) {
33268 targetNode.appendChild(this.wrap);
33273 renderElements : function(n, a, targetNode, bulkRender)
33275 // add some indent caching, this helps performance when rendering a large tree
33276 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33277 var t = n.getOwnerTree();
33278 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33279 if (typeof(n.attributes.html) != 'undefined') {
33280 txt = n.attributes.html;
33282 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33283 var cb = typeof a.checked == 'boolean';
33284 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33285 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33286 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33287 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33288 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33289 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33290 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33291 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33292 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33293 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33296 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33297 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33298 n.nextSibling.ui.getEl(), buf.join(""));
33300 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33303 this.elNode = this.wrap.childNodes[0];
33304 this.ctNode = this.wrap.childNodes[1];
33305 var cs = this.elNode.childNodes;
33306 this.indentNode = cs[0];
33307 this.ecNode = cs[1];
33308 this.iconNode = cs[2];
33311 this.checkbox = cs[3];
33314 this.anchor = cs[index];
33315 this.textNode = cs[index].firstChild;
33318 getAnchor : function(){
33319 return this.anchor;
33322 getTextEl : function(){
33323 return this.textNode;
33326 getIconEl : function(){
33327 return this.iconNode;
33330 isChecked : function(){
33331 return this.checkbox ? this.checkbox.checked : false;
33334 updateExpandIcon : function(){
33336 var n = this.node, c1, c2;
33337 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33338 var hasChild = n.hasChildNodes();
33342 c1 = "x-tree-node-collapsed";
33343 c2 = "x-tree-node-expanded";
33346 c1 = "x-tree-node-expanded";
33347 c2 = "x-tree-node-collapsed";
33350 this.removeClass("x-tree-node-leaf");
33351 this.wasLeaf = false;
33353 if(this.c1 != c1 || this.c2 != c2){
33354 Roo.fly(this.elNode).replaceClass(c1, c2);
33355 this.c1 = c1; this.c2 = c2;
33358 // this changes non-leafs into leafs if they have no children.
33359 // it's not very rational behaviour..
33361 if(!this.wasLeaf && this.node.leaf){
33362 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
33365 this.wasLeaf = true;
33368 var ecc = "x-tree-ec-icon "+cls;
33369 if(this.ecc != ecc){
33370 this.ecNode.className = ecc;
33376 getChildIndent : function(){
33377 if(!this.childIndent){
33381 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
33383 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
33385 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
33390 this.childIndent = buf.join("");
33392 return this.childIndent;
33395 renderIndent : function(){
33398 var p = this.node.parentNode;
33400 indent = p.ui.getChildIndent();
33402 if(this.indentMarkup != indent){ // don't rerender if not required
33403 this.indentNode.innerHTML = indent;
33404 this.indentMarkup = indent;
33406 this.updateExpandIcon();
33411 Roo.tree.RootTreeNodeUI = function(){
33412 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
33414 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
33415 render : function(){
33416 if(!this.rendered){
33417 var targetNode = this.node.ownerTree.innerCt.dom;
33418 this.node.expanded = true;
33419 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
33420 this.wrap = this.ctNode = targetNode.firstChild;
33423 collapse : function(){
33425 expand : function(){
33429 * Ext JS Library 1.1.1
33430 * Copyright(c) 2006-2007, Ext JS, LLC.
33432 * Originally Released Under LGPL - original licence link has changed is not relivant.
33435 * <script type="text/javascript">
33438 * @class Roo.tree.TreeLoader
33439 * @extends Roo.util.Observable
33440 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
33441 * nodes from a specified URL. The response must be a javascript Array definition
33442 * who's elements are node definition objects. eg:
33447 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
33448 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
33455 * The old style respose with just an array is still supported, but not recommended.
33458 * A server request is sent, and child nodes are loaded only when a node is expanded.
33459 * The loading node's id is passed to the server under the parameter name "node" to
33460 * enable the server to produce the correct child nodes.
33462 * To pass extra parameters, an event handler may be attached to the "beforeload"
33463 * event, and the parameters specified in the TreeLoader's baseParams property:
33465 myTreeLoader.on("beforeload", function(treeLoader, node) {
33466 this.baseParams.category = node.attributes.category;
33469 * This would pass an HTTP parameter called "category" to the server containing
33470 * the value of the Node's "category" attribute.
33472 * Creates a new Treeloader.
33473 * @param {Object} config A config object containing config properties.
33475 Roo.tree.TreeLoader = function(config){
33476 this.baseParams = {};
33477 this.requestMethod = "POST";
33478 Roo.apply(this, config);
33483 * @event beforeload
33484 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
33485 * @param {Object} This TreeLoader object.
33486 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33487 * @param {Object} callback The callback function specified in the {@link #load} call.
33492 * Fires when the node has been successfuly loaded.
33493 * @param {Object} This TreeLoader object.
33494 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33495 * @param {Object} response The response object containing the data from the server.
33499 * @event loadexception
33500 * Fires if the network request failed.
33501 * @param {Object} This TreeLoader object.
33502 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33503 * @param {Object} response The response object containing the data from the server.
33505 loadexception : true,
33508 * Fires before a node is created, enabling you to return custom Node types
33509 * @param {Object} This TreeLoader object.
33510 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33515 Roo.tree.TreeLoader.superclass.constructor.call(this);
33518 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33520 * @cfg {String} dataUrl The URL from which to request a Json string which
33521 * specifies an array of node definition object representing the child nodes
33525 * @cfg {String} requestMethod either GET or POST
33526 * defaults to POST (due to BC)
33530 * @cfg {Object} baseParams (optional) An object containing properties which
33531 * specify HTTP parameters to be passed to each request for child nodes.
33534 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33535 * created by this loader. If the attributes sent by the server have an attribute in this object,
33536 * they take priority.
33539 * @cfg {Object} uiProviders (optional) An object containing properties which
33541 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33542 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33543 * <i>uiProvider</i> attribute of a returned child node is a string rather
33544 * than a reference to a TreeNodeUI implementation, this that string value
33545 * is used as a property name in the uiProviders object. You can define the provider named
33546 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33551 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33552 * child nodes before loading.
33554 clearOnLoad : true,
33557 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33558 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33559 * Grid query { data : [ .....] }
33564 * @cfg {String} queryParam (optional)
33565 * Name of the query as it will be passed on the querystring (defaults to 'node')
33566 * eg. the request will be ?node=[id]
33573 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33574 * This is called automatically when a node is expanded, but may be used to reload
33575 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33576 * @param {Roo.tree.TreeNode} node
33577 * @param {Function} callback
33579 load : function(node, callback){
33580 if(this.clearOnLoad){
33581 while(node.firstChild){
33582 node.removeChild(node.firstChild);
33585 if(node.attributes.children){ // preloaded json children
33586 var cs = node.attributes.children;
33587 for(var i = 0, len = cs.length; i < len; i++){
33588 node.appendChild(this.createNode(cs[i]));
33590 if(typeof callback == "function"){
33593 }else if(this.dataUrl){
33594 this.requestData(node, callback);
33598 getParams: function(node){
33599 var buf = [], bp = this.baseParams;
33600 for(var key in bp){
33601 if(typeof bp[key] != "function"){
33602 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33605 var n = this.queryParam === false ? 'node' : this.queryParam;
33606 buf.push(n + "=", encodeURIComponent(node.id));
33607 return buf.join("");
33610 requestData : function(node, callback){
33611 if(this.fireEvent("beforeload", this, node, callback) !== false){
33612 this.transId = Roo.Ajax.request({
33613 method:this.requestMethod,
33614 url: this.dataUrl||this.url,
33615 success: this.handleResponse,
33616 failure: this.handleFailure,
33618 argument: {callback: callback, node: node},
33619 params: this.getParams(node)
33622 // if the load is cancelled, make sure we notify
33623 // the node that we are done
33624 if(typeof callback == "function"){
33630 isLoading : function(){
33631 return this.transId ? true : false;
33634 abort : function(){
33635 if(this.isLoading()){
33636 Roo.Ajax.abort(this.transId);
33641 createNode : function(attr)
33643 // apply baseAttrs, nice idea Corey!
33644 if(this.baseAttrs){
33645 Roo.applyIf(attr, this.baseAttrs);
33647 if(this.applyLoader !== false){
33648 attr.loader = this;
33650 // uiProvider = depreciated..
33652 if(typeof(attr.uiProvider) == 'string'){
33653 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33654 /** eval:var:attr */ eval(attr.uiProvider);
33656 if(typeof(this.uiProviders['default']) != 'undefined') {
33657 attr.uiProvider = this.uiProviders['default'];
33660 this.fireEvent('create', this, attr);
33662 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33664 new Roo.tree.TreeNode(attr) :
33665 new Roo.tree.AsyncTreeNode(attr));
33668 processResponse : function(response, node, callback)
33670 var json = response.responseText;
33673 var o = Roo.decode(json);
33675 if (this.root === false && typeof(o.success) != undefined) {
33676 this.root = 'data'; // the default behaviour for list like data..
33679 if (this.root !== false && !o.success) {
33680 // it's a failure condition.
33681 var a = response.argument;
33682 this.fireEvent("loadexception", this, a.node, response);
33683 Roo.log("Load failed - should have a handler really");
33689 if (this.root !== false) {
33693 for(var i = 0, len = o.length; i < len; i++){
33694 var n = this.createNode(o[i]);
33696 node.appendChild(n);
33699 if(typeof callback == "function"){
33700 callback(this, node);
33703 this.handleFailure(response);
33707 handleResponse : function(response){
33708 this.transId = false;
33709 var a = response.argument;
33710 this.processResponse(response, a.node, a.callback);
33711 this.fireEvent("load", this, a.node, response);
33714 handleFailure : function(response)
33716 // should handle failure better..
33717 this.transId = false;
33718 var a = response.argument;
33719 this.fireEvent("loadexception", this, a.node, response);
33720 if(typeof a.callback == "function"){
33721 a.callback(this, a.node);
33726 * Ext JS Library 1.1.1
33727 * Copyright(c) 2006-2007, Ext JS, LLC.
33729 * Originally Released Under LGPL - original licence link has changed is not relivant.
33732 * <script type="text/javascript">
33736 * @class Roo.tree.TreeFilter
33737 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33738 * @param {TreePanel} tree
33739 * @param {Object} config (optional)
33741 Roo.tree.TreeFilter = function(tree, config){
33743 this.filtered = {};
33744 Roo.apply(this, config);
33747 Roo.tree.TreeFilter.prototype = {
33754 * Filter the data by a specific attribute.
33755 * @param {String/RegExp} value Either string that the attribute value
33756 * should start with or a RegExp to test against the attribute
33757 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33758 * @param {TreeNode} startNode (optional) The node to start the filter at.
33760 filter : function(value, attr, startNode){
33761 attr = attr || "text";
33763 if(typeof value == "string"){
33764 var vlen = value.length;
33765 // auto clear empty filter
33766 if(vlen == 0 && this.clearBlank){
33770 value = value.toLowerCase();
33772 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33774 }else if(value.exec){ // regex?
33776 return value.test(n.attributes[attr]);
33779 throw 'Illegal filter type, must be string or regex';
33781 this.filterBy(f, null, startNode);
33785 * Filter by a function. The passed function will be called with each
33786 * node in the tree (or from the startNode). If the function returns true, the node is kept
33787 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33788 * @param {Function} fn The filter function
33789 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33791 filterBy : function(fn, scope, startNode){
33792 startNode = startNode || this.tree.root;
33793 if(this.autoClear){
33796 var af = this.filtered, rv = this.reverse;
33797 var f = function(n){
33798 if(n == startNode){
33804 var m = fn.call(scope || n, n);
33812 startNode.cascade(f);
33815 if(typeof id != "function"){
33817 if(n && n.parentNode){
33818 n.parentNode.removeChild(n);
33826 * Clears the current filter. Note: with the "remove" option
33827 * set a filter cannot be cleared.
33829 clear : function(){
33831 var af = this.filtered;
33833 if(typeof id != "function"){
33840 this.filtered = {};
33845 * Ext JS Library 1.1.1
33846 * Copyright(c) 2006-2007, Ext JS, LLC.
33848 * Originally Released Under LGPL - original licence link has changed is not relivant.
33851 * <script type="text/javascript">
33856 * @class Roo.tree.TreeSorter
33857 * Provides sorting of nodes in a TreePanel
33859 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33860 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33861 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33862 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33863 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33864 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33866 * @param {TreePanel} tree
33867 * @param {Object} config
33869 Roo.tree.TreeSorter = function(tree, config){
33870 Roo.apply(this, config);
33871 tree.on("beforechildrenrendered", this.doSort, this);
33872 tree.on("append", this.updateSort, this);
33873 tree.on("insert", this.updateSort, this);
33875 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33876 var p = this.property || "text";
33877 var sortType = this.sortType;
33878 var fs = this.folderSort;
33879 var cs = this.caseSensitive === true;
33880 var leafAttr = this.leafAttr || 'leaf';
33882 this.sortFn = function(n1, n2){
33884 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33887 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33891 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33892 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33894 return dsc ? +1 : -1;
33896 return dsc ? -1 : +1;
33903 Roo.tree.TreeSorter.prototype = {
33904 doSort : function(node){
33905 node.sort(this.sortFn);
33908 compareNodes : function(n1, n2){
33909 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33912 updateSort : function(tree, node){
33913 if(node.childrenRendered){
33914 this.doSort.defer(1, this, [node]);
33919 * Ext JS Library 1.1.1
33920 * Copyright(c) 2006-2007, Ext JS, LLC.
33922 * Originally Released Under LGPL - original licence link has changed is not relivant.
33925 * <script type="text/javascript">
33928 if(Roo.dd.DropZone){
33930 Roo.tree.TreeDropZone = function(tree, config){
33931 this.allowParentInsert = false;
33932 this.allowContainerDrop = false;
33933 this.appendOnly = false;
33934 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33936 this.lastInsertClass = "x-tree-no-status";
33937 this.dragOverData = {};
33940 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33941 ddGroup : "TreeDD",
33944 expandDelay : 1000,
33946 expandNode : function(node){
33947 if(node.hasChildNodes() && !node.isExpanded()){
33948 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33952 queueExpand : function(node){
33953 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33956 cancelExpand : function(){
33957 if(this.expandProcId){
33958 clearTimeout(this.expandProcId);
33959 this.expandProcId = false;
33963 isValidDropPoint : function(n, pt, dd, e, data){
33964 if(!n || !data){ return false; }
33965 var targetNode = n.node;
33966 var dropNode = data.node;
33967 // default drop rules
33968 if(!(targetNode && targetNode.isTarget && pt)){
33971 if(pt == "append" && targetNode.allowChildren === false){
33974 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33977 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33980 // reuse the object
33981 var overEvent = this.dragOverData;
33982 overEvent.tree = this.tree;
33983 overEvent.target = targetNode;
33984 overEvent.data = data;
33985 overEvent.point = pt;
33986 overEvent.source = dd;
33987 overEvent.rawEvent = e;
33988 overEvent.dropNode = dropNode;
33989 overEvent.cancel = false;
33990 var result = this.tree.fireEvent("nodedragover", overEvent);
33991 return overEvent.cancel === false && result !== false;
33994 getDropPoint : function(e, n, dd)
33998 return tn.allowChildren !== false ? "append" : false; // always append for root
34000 var dragEl = n.ddel;
34001 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34002 var y = Roo.lib.Event.getPageY(e);
34003 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34005 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34006 var noAppend = tn.allowChildren === false;
34007 if(this.appendOnly || tn.parentNode.allowChildren === false){
34008 return noAppend ? false : "append";
34010 var noBelow = false;
34011 if(!this.allowParentInsert){
34012 noBelow = tn.hasChildNodes() && tn.isExpanded();
34014 var q = (b - t) / (noAppend ? 2 : 3);
34015 if(y >= t && y < (t + q)){
34017 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34024 onNodeEnter : function(n, dd, e, data)
34026 this.cancelExpand();
34029 onNodeOver : function(n, dd, e, data)
34032 var pt = this.getDropPoint(e, n, dd);
34035 // auto node expand check
34036 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34037 this.queueExpand(node);
34038 }else if(pt != "append"){
34039 this.cancelExpand();
34042 // set the insert point style on the target node
34043 var returnCls = this.dropNotAllowed;
34044 if(this.isValidDropPoint(n, pt, dd, e, data)){
34049 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34050 cls = "x-tree-drag-insert-above";
34051 }else if(pt == "below"){
34052 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34053 cls = "x-tree-drag-insert-below";
34055 returnCls = "x-tree-drop-ok-append";
34056 cls = "x-tree-drag-append";
34058 if(this.lastInsertClass != cls){
34059 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34060 this.lastInsertClass = cls;
34067 onNodeOut : function(n, dd, e, data){
34069 this.cancelExpand();
34070 this.removeDropIndicators(n);
34073 onNodeDrop : function(n, dd, e, data){
34074 var point = this.getDropPoint(e, n, dd);
34075 var targetNode = n.node;
34076 targetNode.ui.startDrop();
34077 if(!this.isValidDropPoint(n, point, dd, e, data)){
34078 targetNode.ui.endDrop();
34081 // first try to find the drop node
34082 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34085 target: targetNode,
34090 dropNode: dropNode,
34093 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34094 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34095 targetNode.ui.endDrop();
34098 // allow target changing
34099 targetNode = dropEvent.target;
34100 if(point == "append" && !targetNode.isExpanded()){
34101 targetNode.expand(false, null, function(){
34102 this.completeDrop(dropEvent);
34103 }.createDelegate(this));
34105 this.completeDrop(dropEvent);
34110 completeDrop : function(de){
34111 var ns = de.dropNode, p = de.point, t = de.target;
34112 if(!(ns instanceof Array)){
34116 for(var i = 0, len = ns.length; i < len; i++){
34119 t.parentNode.insertBefore(n, t);
34120 }else if(p == "below"){
34121 t.parentNode.insertBefore(n, t.nextSibling);
34127 if(this.tree.hlDrop){
34131 this.tree.fireEvent("nodedrop", de);
34134 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34135 if(this.tree.hlDrop){
34136 dropNode.ui.focus();
34137 dropNode.ui.highlight();
34139 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34142 getTree : function(){
34146 removeDropIndicators : function(n){
34149 Roo.fly(el).removeClass([
34150 "x-tree-drag-insert-above",
34151 "x-tree-drag-insert-below",
34152 "x-tree-drag-append"]);
34153 this.lastInsertClass = "_noclass";
34157 beforeDragDrop : function(target, e, id){
34158 this.cancelExpand();
34162 afterRepair : function(data){
34163 if(data && Roo.enableFx){
34164 data.node.ui.highlight();
34174 * Ext JS Library 1.1.1
34175 * Copyright(c) 2006-2007, Ext JS, LLC.
34177 * Originally Released Under LGPL - original licence link has changed is not relivant.
34180 * <script type="text/javascript">
34184 if(Roo.dd.DragZone){
34185 Roo.tree.TreeDragZone = function(tree, config){
34186 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34190 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34191 ddGroup : "TreeDD",
34193 onBeforeDrag : function(data, e){
34195 return n && n.draggable && !n.disabled;
34199 onInitDrag : function(e){
34200 var data = this.dragData;
34201 this.tree.getSelectionModel().select(data.node);
34202 this.proxy.update("");
34203 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34204 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34207 getRepairXY : function(e, data){
34208 return data.node.ui.getDDRepairXY();
34211 onEndDrag : function(data, e){
34212 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34217 onValidDrop : function(dd, e, id){
34218 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34222 beforeInvalidDrop : function(e, id){
34223 // this scrolls the original position back into view
34224 var sm = this.tree.getSelectionModel();
34225 sm.clearSelections();
34226 sm.select(this.dragData.node);
34231 * Ext JS Library 1.1.1
34232 * Copyright(c) 2006-2007, Ext JS, LLC.
34234 * Originally Released Under LGPL - original licence link has changed is not relivant.
34237 * <script type="text/javascript">
34240 * @class Roo.tree.TreeEditor
34241 * @extends Roo.Editor
34242 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34243 * as the editor field.
34245 * @param {Object} config (used to be the tree panel.)
34246 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34248 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34249 * @cfg {Roo.form.TextField|Object} field The field configuration
34253 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34256 if (oldconfig) { // old style..
34257 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34260 tree = config.tree;
34261 config.field = config.field || {};
34262 config.field.xtype = 'TextField';
34263 field = Roo.factory(config.field, Roo.form);
34265 config = config || {};
34270 * @event beforenodeedit
34271 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34272 * false from the handler of this event.
34273 * @param {Editor} this
34274 * @param {Roo.tree.Node} node
34276 "beforenodeedit" : true
34280 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34284 tree.on('beforeclick', this.beforeNodeClick, this);
34285 tree.getTreeEl().on('mousedown', this.hide, this);
34286 this.on('complete', this.updateNode, this);
34287 this.on('beforestartedit', this.fitToTree, this);
34288 this.on('startedit', this.bindScroll, this, {delay:10});
34289 this.on('specialkey', this.onSpecialKey, this);
34292 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34294 * @cfg {String} alignment
34295 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34301 * @cfg {Boolean} hideEl
34302 * True to hide the bound element while the editor is displayed (defaults to false)
34306 * @cfg {String} cls
34307 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34309 cls: "x-small-editor x-tree-editor",
34311 * @cfg {Boolean} shim
34312 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34318 * @cfg {Number} maxWidth
34319 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34320 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34321 * scroll and client offsets into account prior to each edit.
34328 fitToTree : function(ed, el){
34329 var td = this.tree.getTreeEl().dom, nd = el.dom;
34330 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34331 td.scrollLeft = nd.offsetLeft;
34335 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34336 this.setSize(w, '');
34338 return this.fireEvent('beforenodeedit', this, this.editNode);
34343 triggerEdit : function(node){
34344 this.completeEdit();
34345 this.editNode = node;
34346 this.startEdit(node.ui.textNode, node.text);
34350 bindScroll : function(){
34351 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34355 beforeNodeClick : function(node, e){
34356 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34357 this.lastClick = new Date();
34358 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34360 this.triggerEdit(node);
34367 updateNode : function(ed, value){
34368 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
34369 this.editNode.setText(value);
34373 onHide : function(){
34374 Roo.tree.TreeEditor.superclass.onHide.call(this);
34376 this.editNode.ui.focus();
34381 onSpecialKey : function(field, e){
34382 var k = e.getKey();
34386 }else if(k == e.ENTER && !e.hasModifier()){
34388 this.completeEdit();
34391 });//<Script type="text/javascript">
34394 * Ext JS Library 1.1.1
34395 * Copyright(c) 2006-2007, Ext JS, LLC.
34397 * Originally Released Under LGPL - original licence link has changed is not relivant.
34400 * <script type="text/javascript">
34404 * Not documented??? - probably should be...
34407 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
34408 //focus: Roo.emptyFn, // prevent odd scrolling behavior
34410 renderElements : function(n, a, targetNode, bulkRender){
34411 //consel.log("renderElements?");
34412 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34414 var t = n.getOwnerTree();
34415 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
34417 var cols = t.columns;
34418 var bw = t.borderWidth;
34420 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34421 var cb = typeof a.checked == "boolean";
34422 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34423 var colcls = 'x-t-' + tid + '-c0';
34425 '<li class="x-tree-node">',
34428 '<div class="x-tree-node-el ', a.cls,'">',
34430 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
34433 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
34434 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
34435 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
34436 (a.icon ? ' x-tree-node-inline-icon' : ''),
34437 (a.iconCls ? ' '+a.iconCls : ''),
34438 '" unselectable="on" />',
34439 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
34440 (a.checked ? 'checked="checked" />' : ' />')) : ''),
34442 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34443 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
34444 '<span unselectable="on" qtip="' + tx + '">',
34448 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34449 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
34451 for(var i = 1, len = cols.length; i < len; i++){
34453 colcls = 'x-t-' + tid + '-c' +i;
34454 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34455 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
34456 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
34462 '<div class="x-clear"></div></div>',
34463 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34466 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34467 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34468 n.nextSibling.ui.getEl(), buf.join(""));
34470 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34472 var el = this.wrap.firstChild;
34474 this.elNode = el.firstChild;
34475 this.ranchor = el.childNodes[1];
34476 this.ctNode = this.wrap.childNodes[1];
34477 var cs = el.firstChild.childNodes;
34478 this.indentNode = cs[0];
34479 this.ecNode = cs[1];
34480 this.iconNode = cs[2];
34483 this.checkbox = cs[3];
34486 this.anchor = cs[index];
34488 this.textNode = cs[index].firstChild;
34490 //el.on("click", this.onClick, this);
34491 //el.on("dblclick", this.onDblClick, this);
34494 // console.log(this);
34496 initEvents : function(){
34497 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34500 var a = this.ranchor;
34502 var el = Roo.get(a);
34504 if(Roo.isOpera){ // opera render bug ignores the CSS
34505 el.setStyle("text-decoration", "none");
34508 el.on("click", this.onClick, this);
34509 el.on("dblclick", this.onDblClick, this);
34510 el.on("contextmenu", this.onContextMenu, this);
34514 /*onSelectedChange : function(state){
34517 this.addClass("x-tree-selected");
34520 this.removeClass("x-tree-selected");
34523 addClass : function(cls){
34525 Roo.fly(this.elRow).addClass(cls);
34531 removeClass : function(cls){
34533 Roo.fly(this.elRow).removeClass(cls);
34539 });//<Script type="text/javascript">
34543 * Ext JS Library 1.1.1
34544 * Copyright(c) 2006-2007, Ext JS, LLC.
34546 * Originally Released Under LGPL - original licence link has changed is not relivant.
34549 * <script type="text/javascript">
34554 * @class Roo.tree.ColumnTree
34555 * @extends Roo.data.TreePanel
34556 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34557 * @cfg {int} borderWidth compined right/left border allowance
34559 * @param {String/HTMLElement/Element} el The container element
34560 * @param {Object} config
34562 Roo.tree.ColumnTree = function(el, config)
34564 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34568 * Fire this event on a container when it resizes
34569 * @param {int} w Width
34570 * @param {int} h Height
34574 this.on('resize', this.onResize, this);
34577 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34581 borderWidth: Roo.isBorderBox ? 0 : 2,
34584 render : function(){
34585 // add the header.....
34587 Roo.tree.ColumnTree.superclass.render.apply(this);
34589 this.el.addClass('x-column-tree');
34591 this.headers = this.el.createChild(
34592 {cls:'x-tree-headers'},this.innerCt.dom);
34594 var cols = this.columns, c;
34595 var totalWidth = 0;
34597 var len = cols.length;
34598 for(var i = 0; i < len; i++){
34600 totalWidth += c.width;
34601 this.headEls.push(this.headers.createChild({
34602 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34604 cls:'x-tree-hd-text',
34607 style:'width:'+(c.width-this.borderWidth)+'px;'
34610 this.headers.createChild({cls:'x-clear'});
34611 // prevent floats from wrapping when clipped
34612 this.headers.setWidth(totalWidth);
34613 //this.innerCt.setWidth(totalWidth);
34614 this.innerCt.setStyle({ overflow: 'auto' });
34615 this.onResize(this.width, this.height);
34619 onResize : function(w,h)
34624 this.innerCt.setWidth(this.width);
34625 this.innerCt.setHeight(this.height-20);
34628 var cols = this.columns, c;
34629 var totalWidth = 0;
34631 var len = cols.length;
34632 for(var i = 0; i < len; i++){
34634 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34635 // it's the expander..
34636 expEl = this.headEls[i];
34639 totalWidth += c.width;
34643 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34645 this.headers.setWidth(w-20);
34654 * Ext JS Library 1.1.1
34655 * Copyright(c) 2006-2007, Ext JS, LLC.
34657 * Originally Released Under LGPL - original licence link has changed is not relivant.
34660 * <script type="text/javascript">
34664 * @class Roo.menu.Menu
34665 * @extends Roo.util.Observable
34666 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34667 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34669 * Creates a new Menu
34670 * @param {Object} config Configuration options
34672 Roo.menu.Menu = function(config){
34673 Roo.apply(this, config);
34674 this.id = this.id || Roo.id();
34677 * @event beforeshow
34678 * Fires before this menu is displayed
34679 * @param {Roo.menu.Menu} this
34683 * @event beforehide
34684 * Fires before this menu is hidden
34685 * @param {Roo.menu.Menu} this
34690 * Fires after this menu is displayed
34691 * @param {Roo.menu.Menu} this
34696 * Fires after this menu is hidden
34697 * @param {Roo.menu.Menu} this
34702 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34703 * @param {Roo.menu.Menu} this
34704 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34705 * @param {Roo.EventObject} e
34710 * Fires when the mouse is hovering over this menu
34711 * @param {Roo.menu.Menu} this
34712 * @param {Roo.EventObject} e
34713 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34718 * Fires when the mouse exits this menu
34719 * @param {Roo.menu.Menu} this
34720 * @param {Roo.EventObject} e
34721 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34726 * Fires when a menu item contained in this menu is clicked
34727 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34728 * @param {Roo.EventObject} e
34732 if (this.registerMenu) {
34733 Roo.menu.MenuMgr.register(this);
34736 var mis = this.items;
34737 this.items = new Roo.util.MixedCollection();
34739 this.add.apply(this, mis);
34743 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34745 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34749 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34750 * for bottom-right shadow (defaults to "sides")
34754 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34755 * this menu (defaults to "tl-tr?")
34757 subMenuAlign : "tl-tr?",
34759 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34760 * relative to its element of origin (defaults to "tl-bl?")
34762 defaultAlign : "tl-bl?",
34764 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34766 allowOtherMenus : false,
34768 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34770 registerMenu : true,
34775 render : function(){
34779 var el = this.el = new Roo.Layer({
34781 shadow:this.shadow,
34783 parentEl: this.parentEl || document.body,
34787 this.keyNav = new Roo.menu.MenuNav(this);
34790 el.addClass("x-menu-plain");
34793 el.addClass(this.cls);
34795 // generic focus element
34796 this.focusEl = el.createChild({
34797 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34799 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34800 ul.on("click", this.onClick, this);
34801 ul.on("mouseover", this.onMouseOver, this);
34802 ul.on("mouseout", this.onMouseOut, this);
34803 this.items.each(function(item){
34804 var li = document.createElement("li");
34805 li.className = "x-menu-list-item";
34806 ul.dom.appendChild(li);
34807 item.render(li, this);
34814 autoWidth : function(){
34815 var el = this.el, ul = this.ul;
34819 var w = this.width;
34822 }else if(Roo.isIE){
34823 el.setWidth(this.minWidth);
34824 var t = el.dom.offsetWidth; // force recalc
34825 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34830 delayAutoWidth : function(){
34833 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34835 this.awTask.delay(20);
34840 findTargetItem : function(e){
34841 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34842 if(t && t.menuItemId){
34843 return this.items.get(t.menuItemId);
34848 onClick : function(e){
34850 if(t = this.findTargetItem(e)){
34852 this.fireEvent("click", this, t, e);
34857 setActiveItem : function(item, autoExpand){
34858 if(item != this.activeItem){
34859 if(this.activeItem){
34860 this.activeItem.deactivate();
34862 this.activeItem = item;
34863 item.activate(autoExpand);
34864 }else if(autoExpand){
34870 tryActivate : function(start, step){
34871 var items = this.items;
34872 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34873 var item = items.get(i);
34874 if(!item.disabled && item.canActivate){
34875 this.setActiveItem(item, false);
34883 onMouseOver : function(e){
34885 if(t = this.findTargetItem(e)){
34886 if(t.canActivate && !t.disabled){
34887 this.setActiveItem(t, true);
34890 this.fireEvent("mouseover", this, e, t);
34894 onMouseOut : function(e){
34896 if(t = this.findTargetItem(e)){
34897 if(t == this.activeItem && t.shouldDeactivate(e)){
34898 this.activeItem.deactivate();
34899 delete this.activeItem;
34902 this.fireEvent("mouseout", this, e, t);
34906 * Read-only. Returns true if the menu is currently displayed, else false.
34909 isVisible : function(){
34910 return this.el && !this.hidden;
34914 * Displays this menu relative to another element
34915 * @param {String/HTMLElement/Roo.Element} element The element to align to
34916 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34917 * the element (defaults to this.defaultAlign)
34918 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34920 show : function(el, pos, parentMenu){
34921 this.parentMenu = parentMenu;
34925 this.fireEvent("beforeshow", this);
34926 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34930 * Displays this menu at a specific xy position
34931 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34932 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34934 showAt : function(xy, parentMenu, /* private: */_e){
34935 this.parentMenu = parentMenu;
34940 this.fireEvent("beforeshow", this);
34941 xy = this.el.adjustForConstraints(xy);
34945 this.hidden = false;
34947 this.fireEvent("show", this);
34950 focus : function(){
34952 this.doFocus.defer(50, this);
34956 doFocus : function(){
34958 this.focusEl.focus();
34963 * Hides this menu and optionally all parent menus
34964 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34966 hide : function(deep){
34967 if(this.el && this.isVisible()){
34968 this.fireEvent("beforehide", this);
34969 if(this.activeItem){
34970 this.activeItem.deactivate();
34971 this.activeItem = null;
34974 this.hidden = true;
34975 this.fireEvent("hide", this);
34977 if(deep === true && this.parentMenu){
34978 this.parentMenu.hide(true);
34983 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34984 * Any of the following are valid:
34986 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34987 * <li>An HTMLElement object which will be converted to a menu item</li>
34988 * <li>A menu item config object that will be created as a new menu item</li>
34989 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34990 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34995 var menu = new Roo.menu.Menu();
34997 // Create a menu item to add by reference
34998 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35000 // Add a bunch of items at once using different methods.
35001 // Only the last item added will be returned.
35002 var item = menu.add(
35003 menuItem, // add existing item by ref
35004 'Dynamic Item', // new TextItem
35005 '-', // new separator
35006 { text: 'Config Item' } // new item by config
35009 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35010 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35013 var a = arguments, l = a.length, item;
35014 for(var i = 0; i < l; i++){
35016 if ((typeof(el) == "object") && el.xtype && el.xns) {
35017 el = Roo.factory(el, Roo.menu);
35020 if(el.render){ // some kind of Item
35021 item = this.addItem(el);
35022 }else if(typeof el == "string"){ // string
35023 if(el == "separator" || el == "-"){
35024 item = this.addSeparator();
35026 item = this.addText(el);
35028 }else if(el.tagName || el.el){ // element
35029 item = this.addElement(el);
35030 }else if(typeof el == "object"){ // must be menu item config?
35031 item = this.addMenuItem(el);
35038 * Returns this menu's underlying {@link Roo.Element} object
35039 * @return {Roo.Element} The element
35041 getEl : function(){
35049 * Adds a separator bar to the menu
35050 * @return {Roo.menu.Item} The menu item that was added
35052 addSeparator : function(){
35053 return this.addItem(new Roo.menu.Separator());
35057 * Adds an {@link Roo.Element} object to the menu
35058 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35059 * @return {Roo.menu.Item} The menu item that was added
35061 addElement : function(el){
35062 return this.addItem(new Roo.menu.BaseItem(el));
35066 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35067 * @param {Roo.menu.Item} item The menu item to add
35068 * @return {Roo.menu.Item} The menu item that was added
35070 addItem : function(item){
35071 this.items.add(item);
35073 var li = document.createElement("li");
35074 li.className = "x-menu-list-item";
35075 this.ul.dom.appendChild(li);
35076 item.render(li, this);
35077 this.delayAutoWidth();
35083 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35084 * @param {Object} config A MenuItem config object
35085 * @return {Roo.menu.Item} The menu item that was added
35087 addMenuItem : function(config){
35088 if(!(config instanceof Roo.menu.Item)){
35089 if(typeof config.checked == "boolean"){ // must be check menu item config?
35090 config = new Roo.menu.CheckItem(config);
35092 config = new Roo.menu.Item(config);
35095 return this.addItem(config);
35099 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35100 * @param {String} text The text to display in the menu item
35101 * @return {Roo.menu.Item} The menu item that was added
35103 addText : function(text){
35104 return this.addItem(new Roo.menu.TextItem({ text : text }));
35108 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35109 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35110 * @param {Roo.menu.Item} item The menu item to add
35111 * @return {Roo.menu.Item} The menu item that was added
35113 insert : function(index, item){
35114 this.items.insert(index, item);
35116 var li = document.createElement("li");
35117 li.className = "x-menu-list-item";
35118 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35119 item.render(li, this);
35120 this.delayAutoWidth();
35126 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35127 * @param {Roo.menu.Item} item The menu item to remove
35129 remove : function(item){
35130 this.items.removeKey(item.id);
35135 * Removes and destroys all items in the menu
35137 removeAll : function(){
35139 while(f = this.items.first()){
35145 // MenuNav is a private utility class used internally by the Menu
35146 Roo.menu.MenuNav = function(menu){
35147 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35148 this.scope = this.menu = menu;
35151 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35152 doRelay : function(e, h){
35153 var k = e.getKey();
35154 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35155 this.menu.tryActivate(0, 1);
35158 return h.call(this.scope || this, e, this.menu);
35161 up : function(e, m){
35162 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35163 m.tryActivate(m.items.length-1, -1);
35167 down : function(e, m){
35168 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35169 m.tryActivate(0, 1);
35173 right : function(e, m){
35175 m.activeItem.expandMenu(true);
35179 left : function(e, m){
35181 if(m.parentMenu && m.parentMenu.activeItem){
35182 m.parentMenu.activeItem.activate();
35186 enter : function(e, m){
35188 e.stopPropagation();
35189 m.activeItem.onClick(e);
35190 m.fireEvent("click", this, m.activeItem);
35196 * Ext JS Library 1.1.1
35197 * Copyright(c) 2006-2007, Ext JS, LLC.
35199 * Originally Released Under LGPL - original licence link has changed is not relivant.
35202 * <script type="text/javascript">
35206 * @class Roo.menu.MenuMgr
35207 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35210 Roo.menu.MenuMgr = function(){
35211 var menus, active, groups = {}, attached = false, lastShow = new Date();
35213 // private - called when first menu is created
35216 active = new Roo.util.MixedCollection();
35217 Roo.get(document).addKeyListener(27, function(){
35218 if(active.length > 0){
35225 function hideAll(){
35226 if(active && active.length > 0){
35227 var c = active.clone();
35228 c.each(function(m){
35235 function onHide(m){
35237 if(active.length < 1){
35238 Roo.get(document).un("mousedown", onMouseDown);
35244 function onShow(m){
35245 var last = active.last();
35246 lastShow = new Date();
35249 Roo.get(document).on("mousedown", onMouseDown);
35253 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35254 m.parentMenu.activeChild = m;
35255 }else if(last && last.isVisible()){
35256 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35261 function onBeforeHide(m){
35263 m.activeChild.hide();
35265 if(m.autoHideTimer){
35266 clearTimeout(m.autoHideTimer);
35267 delete m.autoHideTimer;
35272 function onBeforeShow(m){
35273 var pm = m.parentMenu;
35274 if(!pm && !m.allowOtherMenus){
35276 }else if(pm && pm.activeChild && active != m){
35277 pm.activeChild.hide();
35282 function onMouseDown(e){
35283 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35289 function onBeforeCheck(mi, state){
35291 var g = groups[mi.group];
35292 for(var i = 0, l = g.length; i < l; i++){
35294 g[i].setChecked(false);
35303 * Hides all menus that are currently visible
35305 hideAll : function(){
35310 register : function(menu){
35314 menus[menu.id] = menu;
35315 menu.on("beforehide", onBeforeHide);
35316 menu.on("hide", onHide);
35317 menu.on("beforeshow", onBeforeShow);
35318 menu.on("show", onShow);
35319 var g = menu.group;
35320 if(g && menu.events["checkchange"]){
35324 groups[g].push(menu);
35325 menu.on("checkchange", onCheck);
35330 * Returns a {@link Roo.menu.Menu} object
35331 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35332 * be used to generate and return a new Menu instance.
35334 get : function(menu){
35335 if(typeof menu == "string"){ // menu id
35336 return menus[menu];
35337 }else if(menu.events){ // menu instance
35339 }else if(typeof menu.length == 'number'){ // array of menu items?
35340 return new Roo.menu.Menu({items:menu});
35341 }else{ // otherwise, must be a config
35342 return new Roo.menu.Menu(menu);
35347 unregister : function(menu){
35348 delete menus[menu.id];
35349 menu.un("beforehide", onBeforeHide);
35350 menu.un("hide", onHide);
35351 menu.un("beforeshow", onBeforeShow);
35352 menu.un("show", onShow);
35353 var g = menu.group;
35354 if(g && menu.events["checkchange"]){
35355 groups[g].remove(menu);
35356 menu.un("checkchange", onCheck);
35361 registerCheckable : function(menuItem){
35362 var g = menuItem.group;
35367 groups[g].push(menuItem);
35368 menuItem.on("beforecheckchange", onBeforeCheck);
35373 unregisterCheckable : function(menuItem){
35374 var g = menuItem.group;
35376 groups[g].remove(menuItem);
35377 menuItem.un("beforecheckchange", onBeforeCheck);
35383 * Ext JS Library 1.1.1
35384 * Copyright(c) 2006-2007, Ext JS, LLC.
35386 * Originally Released Under LGPL - original licence link has changed is not relivant.
35389 * <script type="text/javascript">
35394 * @class Roo.menu.BaseItem
35395 * @extends Roo.Component
35396 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
35397 * management and base configuration options shared by all menu components.
35399 * Creates a new BaseItem
35400 * @param {Object} config Configuration options
35402 Roo.menu.BaseItem = function(config){
35403 Roo.menu.BaseItem.superclass.constructor.call(this, config);
35408 * Fires when this item is clicked
35409 * @param {Roo.menu.BaseItem} this
35410 * @param {Roo.EventObject} e
35415 * Fires when this item is activated
35416 * @param {Roo.menu.BaseItem} this
35420 * @event deactivate
35421 * Fires when this item is deactivated
35422 * @param {Roo.menu.BaseItem} this
35428 this.on("click", this.handler, this.scope, true);
35432 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
35434 * @cfg {Function} handler
35435 * A function that will handle the click event of this menu item (defaults to undefined)
35438 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
35440 canActivate : false,
35442 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
35444 activeClass : "x-menu-item-active",
35446 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
35448 hideOnClick : true,
35450 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
35455 ctype: "Roo.menu.BaseItem",
35458 actionMode : "container",
35461 render : function(container, parentMenu){
35462 this.parentMenu = parentMenu;
35463 Roo.menu.BaseItem.superclass.render.call(this, container);
35464 this.container.menuItemId = this.id;
35468 onRender : function(container, position){
35469 this.el = Roo.get(this.el);
35470 container.dom.appendChild(this.el.dom);
35474 onClick : function(e){
35475 if(!this.disabled && this.fireEvent("click", this, e) !== false
35476 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
35477 this.handleClick(e);
35484 activate : function(){
35488 var li = this.container;
35489 li.addClass(this.activeClass);
35490 this.region = li.getRegion().adjust(2, 2, -2, -2);
35491 this.fireEvent("activate", this);
35496 deactivate : function(){
35497 this.container.removeClass(this.activeClass);
35498 this.fireEvent("deactivate", this);
35502 shouldDeactivate : function(e){
35503 return !this.region || !this.region.contains(e.getPoint());
35507 handleClick : function(e){
35508 if(this.hideOnClick){
35509 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35514 expandMenu : function(autoActivate){
35519 hideMenu : function(){
35524 * Ext JS Library 1.1.1
35525 * Copyright(c) 2006-2007, Ext JS, LLC.
35527 * Originally Released Under LGPL - original licence link has changed is not relivant.
35530 * <script type="text/javascript">
35534 * @class Roo.menu.Adapter
35535 * @extends Roo.menu.BaseItem
35536 * 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.
35537 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35539 * Creates a new Adapter
35540 * @param {Object} config Configuration options
35542 Roo.menu.Adapter = function(component, config){
35543 Roo.menu.Adapter.superclass.constructor.call(this, config);
35544 this.component = component;
35546 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35548 canActivate : true,
35551 onRender : function(container, position){
35552 this.component.render(container);
35553 this.el = this.component.getEl();
35557 activate : function(){
35561 this.component.focus();
35562 this.fireEvent("activate", this);
35567 deactivate : function(){
35568 this.fireEvent("deactivate", this);
35572 disable : function(){
35573 this.component.disable();
35574 Roo.menu.Adapter.superclass.disable.call(this);
35578 enable : function(){
35579 this.component.enable();
35580 Roo.menu.Adapter.superclass.enable.call(this);
35584 * Ext JS Library 1.1.1
35585 * Copyright(c) 2006-2007, Ext JS, LLC.
35587 * Originally Released Under LGPL - original licence link has changed is not relivant.
35590 * <script type="text/javascript">
35594 * @class Roo.menu.TextItem
35595 * @extends Roo.menu.BaseItem
35596 * Adds a static text string to a menu, usually used as either a heading or group separator.
35597 * Note: old style constructor with text is still supported.
35600 * Creates a new TextItem
35601 * @param {Object} cfg Configuration
35603 Roo.menu.TextItem = function(cfg){
35604 if (typeof(cfg) == 'string') {
35607 Roo.apply(this,cfg);
35610 Roo.menu.TextItem.superclass.constructor.call(this);
35613 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35615 * @cfg {Boolean} text Text to show on item.
35620 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35622 hideOnClick : false,
35624 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35626 itemCls : "x-menu-text",
35629 onRender : function(){
35630 var s = document.createElement("span");
35631 s.className = this.itemCls;
35632 s.innerHTML = this.text;
35634 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35638 * Ext JS Library 1.1.1
35639 * Copyright(c) 2006-2007, Ext JS, LLC.
35641 * Originally Released Under LGPL - original licence link has changed is not relivant.
35644 * <script type="text/javascript">
35648 * @class Roo.menu.Separator
35649 * @extends Roo.menu.BaseItem
35650 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35651 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35653 * @param {Object} config Configuration options
35655 Roo.menu.Separator = function(config){
35656 Roo.menu.Separator.superclass.constructor.call(this, config);
35659 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35661 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35663 itemCls : "x-menu-sep",
35665 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35667 hideOnClick : false,
35670 onRender : function(li){
35671 var s = document.createElement("span");
35672 s.className = this.itemCls;
35673 s.innerHTML = " ";
35675 li.addClass("x-menu-sep-li");
35676 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35680 * Ext JS Library 1.1.1
35681 * Copyright(c) 2006-2007, Ext JS, LLC.
35683 * Originally Released Under LGPL - original licence link has changed is not relivant.
35686 * <script type="text/javascript">
35689 * @class Roo.menu.Item
35690 * @extends Roo.menu.BaseItem
35691 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35692 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35693 * activation and click handling.
35695 * Creates a new Item
35696 * @param {Object} config Configuration options
35698 Roo.menu.Item = function(config){
35699 Roo.menu.Item.superclass.constructor.call(this, config);
35701 this.menu = Roo.menu.MenuMgr.get(this.menu);
35704 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35707 * @cfg {String} text
35708 * The text to show on the menu item.
35712 * @cfg {String} HTML to render in menu
35713 * The text to show on the menu item (HTML version).
35717 * @cfg {String} icon
35718 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35722 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35724 itemCls : "x-menu-item",
35726 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35728 canActivate : true,
35730 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35733 // doc'd in BaseItem
35737 ctype: "Roo.menu.Item",
35740 onRender : function(container, position){
35741 var el = document.createElement("a");
35742 el.hideFocus = true;
35743 el.unselectable = "on";
35744 el.href = this.href || "#";
35745 if(this.hrefTarget){
35746 el.target = this.hrefTarget;
35748 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35750 var html = this.html.length ? this.html : String.format('{0}',this.text);
35752 el.innerHTML = String.format(
35753 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35754 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35756 Roo.menu.Item.superclass.onRender.call(this, container, position);
35760 * Sets the text to display in this menu item
35761 * @param {String} text The text to display
35762 * @param {Boolean} isHTML true to indicate text is pure html.
35764 setText : function(text, isHTML){
35772 var html = this.html.length ? this.html : String.format('{0}',this.text);
35774 this.el.update(String.format(
35775 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35776 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35777 this.parentMenu.autoWidth();
35782 handleClick : function(e){
35783 if(!this.href){ // if no link defined, stop the event automatically
35786 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35790 activate : function(autoExpand){
35791 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35801 shouldDeactivate : function(e){
35802 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35803 if(this.menu && this.menu.isVisible()){
35804 return !this.menu.getEl().getRegion().contains(e.getPoint());
35812 deactivate : function(){
35813 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35818 expandMenu : function(autoActivate){
35819 if(!this.disabled && this.menu){
35820 clearTimeout(this.hideTimer);
35821 delete this.hideTimer;
35822 if(!this.menu.isVisible() && !this.showTimer){
35823 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35824 }else if (this.menu.isVisible() && autoActivate){
35825 this.menu.tryActivate(0, 1);
35831 deferExpand : function(autoActivate){
35832 delete this.showTimer;
35833 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35835 this.menu.tryActivate(0, 1);
35840 hideMenu : function(){
35841 clearTimeout(this.showTimer);
35842 delete this.showTimer;
35843 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35844 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35849 deferHide : function(){
35850 delete this.hideTimer;
35855 * Ext JS Library 1.1.1
35856 * Copyright(c) 2006-2007, Ext JS, LLC.
35858 * Originally Released Under LGPL - original licence link has changed is not relivant.
35861 * <script type="text/javascript">
35865 * @class Roo.menu.CheckItem
35866 * @extends Roo.menu.Item
35867 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35869 * Creates a new CheckItem
35870 * @param {Object} config Configuration options
35872 Roo.menu.CheckItem = function(config){
35873 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35876 * @event beforecheckchange
35877 * Fires before the checked value is set, providing an opportunity to cancel if needed
35878 * @param {Roo.menu.CheckItem} this
35879 * @param {Boolean} checked The new checked value that will be set
35881 "beforecheckchange" : true,
35883 * @event checkchange
35884 * Fires after the checked value has been set
35885 * @param {Roo.menu.CheckItem} this
35886 * @param {Boolean} checked The checked value that was set
35888 "checkchange" : true
35890 if(this.checkHandler){
35891 this.on('checkchange', this.checkHandler, this.scope);
35894 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35896 * @cfg {String} group
35897 * All check items with the same group name will automatically be grouped into a single-select
35898 * radio button group (defaults to '')
35901 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35903 itemCls : "x-menu-item x-menu-check-item",
35905 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35907 groupClass : "x-menu-group-item",
35910 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35911 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35912 * initialized with checked = true will be rendered as checked.
35917 ctype: "Roo.menu.CheckItem",
35920 onRender : function(c){
35921 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35923 this.el.addClass(this.groupClass);
35925 Roo.menu.MenuMgr.registerCheckable(this);
35927 this.checked = false;
35928 this.setChecked(true, true);
35933 destroy : function(){
35935 Roo.menu.MenuMgr.unregisterCheckable(this);
35937 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35941 * Set the checked state of this item
35942 * @param {Boolean} checked The new checked value
35943 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35945 setChecked : function(state, suppressEvent){
35946 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35947 if(this.container){
35948 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35950 this.checked = state;
35951 if(suppressEvent !== true){
35952 this.fireEvent("checkchange", this, state);
35958 handleClick : function(e){
35959 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35960 this.setChecked(!this.checked);
35962 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35966 * Ext JS Library 1.1.1
35967 * Copyright(c) 2006-2007, Ext JS, LLC.
35969 * Originally Released Under LGPL - original licence link has changed is not relivant.
35972 * <script type="text/javascript">
35976 * @class Roo.menu.DateItem
35977 * @extends Roo.menu.Adapter
35978 * A menu item that wraps the {@link Roo.DatPicker} component.
35980 * Creates a new DateItem
35981 * @param {Object} config Configuration options
35983 Roo.menu.DateItem = function(config){
35984 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35985 /** The Roo.DatePicker object @type Roo.DatePicker */
35986 this.picker = this.component;
35987 this.addEvents({select: true});
35989 this.picker.on("render", function(picker){
35990 picker.getEl().swallowEvent("click");
35991 picker.container.addClass("x-menu-date-item");
35994 this.picker.on("select", this.onSelect, this);
35997 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35999 onSelect : function(picker, date){
36000 this.fireEvent("select", this, date, picker);
36001 Roo.menu.DateItem.superclass.handleClick.call(this);
36005 * Ext JS Library 1.1.1
36006 * Copyright(c) 2006-2007, Ext JS, LLC.
36008 * Originally Released Under LGPL - original licence link has changed is not relivant.
36011 * <script type="text/javascript">
36015 * @class Roo.menu.ColorItem
36016 * @extends Roo.menu.Adapter
36017 * A menu item that wraps the {@link Roo.ColorPalette} component.
36019 * Creates a new ColorItem
36020 * @param {Object} config Configuration options
36022 Roo.menu.ColorItem = function(config){
36023 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36024 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36025 this.palette = this.component;
36026 this.relayEvents(this.palette, ["select"]);
36027 if(this.selectHandler){
36028 this.on('select', this.selectHandler, this.scope);
36031 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36033 * Ext JS Library 1.1.1
36034 * Copyright(c) 2006-2007, Ext JS, LLC.
36036 * Originally Released Under LGPL - original licence link has changed is not relivant.
36039 * <script type="text/javascript">
36044 * @class Roo.menu.DateMenu
36045 * @extends Roo.menu.Menu
36046 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36048 * Creates a new DateMenu
36049 * @param {Object} config Configuration options
36051 Roo.menu.DateMenu = function(config){
36052 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36054 var di = new Roo.menu.DateItem(config);
36057 * The {@link Roo.DatePicker} instance for this DateMenu
36060 this.picker = di.picker;
36063 * @param {DatePicker} picker
36064 * @param {Date} date
36066 this.relayEvents(di, ["select"]);
36067 this.on('beforeshow', function(){
36069 this.picker.hideMonthPicker(false);
36073 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36077 * Ext JS Library 1.1.1
36078 * Copyright(c) 2006-2007, Ext JS, LLC.
36080 * Originally Released Under LGPL - original licence link has changed is not relivant.
36083 * <script type="text/javascript">
36088 * @class Roo.menu.ColorMenu
36089 * @extends Roo.menu.Menu
36090 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36092 * Creates a new ColorMenu
36093 * @param {Object} config Configuration options
36095 Roo.menu.ColorMenu = function(config){
36096 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36098 var ci = new Roo.menu.ColorItem(config);
36101 * The {@link Roo.ColorPalette} instance for this ColorMenu
36102 * @type ColorPalette
36104 this.palette = ci.palette;
36107 * @param {ColorPalette} palette
36108 * @param {String} color
36110 this.relayEvents(ci, ["select"]);
36112 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36114 * Ext JS Library 1.1.1
36115 * Copyright(c) 2006-2007, Ext JS, LLC.
36117 * Originally Released Under LGPL - original licence link has changed is not relivant.
36120 * <script type="text/javascript">
36124 * @class Roo.form.Field
36125 * @extends Roo.BoxComponent
36126 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36128 * Creates a new Field
36129 * @param {Object} config Configuration options
36131 Roo.form.Field = function(config){
36132 Roo.form.Field.superclass.constructor.call(this, config);
36135 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36137 * @cfg {String} fieldLabel Label to use when rendering a form.
36140 * @cfg {String} qtip Mouse over tip
36144 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36146 invalidClass : "x-form-invalid",
36148 * @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")
36150 invalidText : "The value in this field is invalid",
36152 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36154 focusClass : "x-form-focus",
36156 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36157 automatic validation (defaults to "keyup").
36159 validationEvent : "keyup",
36161 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36163 validateOnBlur : true,
36165 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36167 validationDelay : 250,
36169 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36170 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36172 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36174 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36176 fieldClass : "x-form-field",
36178 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36181 ----------- ----------------------------------------------------------------------
36182 qtip Display a quick tip when the user hovers over the field
36183 title Display a default browser title attribute popup
36184 under Add a block div beneath the field containing the error text
36185 side Add an error icon to the right of the field with a popup on hover
36186 [element id] Add the error text directly to the innerHTML of the specified element
36189 msgTarget : 'qtip',
36191 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36196 * @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.
36201 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36206 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36208 inputType : undefined,
36211 * @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).
36213 tabIndex : undefined,
36216 isFormField : true,
36221 * @property {Roo.Element} fieldEl
36222 * Element Containing the rendered Field (with label etc.)
36225 * @cfg {Mixed} value A value to initialize this field with.
36230 * @cfg {String} name The field's HTML name attribute.
36233 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36237 initComponent : function(){
36238 Roo.form.Field.superclass.initComponent.call(this);
36242 * Fires when this field receives input focus.
36243 * @param {Roo.form.Field} this
36248 * Fires when this field loses input focus.
36249 * @param {Roo.form.Field} this
36253 * @event specialkey
36254 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36255 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36256 * @param {Roo.form.Field} this
36257 * @param {Roo.EventObject} e The event object
36262 * Fires just before the field blurs if the field value has changed.
36263 * @param {Roo.form.Field} this
36264 * @param {Mixed} newValue The new value
36265 * @param {Mixed} oldValue The original value
36270 * Fires after the field has been marked as invalid.
36271 * @param {Roo.form.Field} this
36272 * @param {String} msg The validation message
36277 * Fires after the field has been validated with no errors.
36278 * @param {Roo.form.Field} this
36283 * Fires after the key up
36284 * @param {Roo.form.Field} this
36285 * @param {Roo.EventObject} e The event Object
36292 * Returns the name attribute of the field if available
36293 * @return {String} name The field name
36295 getName: function(){
36296 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36300 onRender : function(ct, position){
36301 Roo.form.Field.superclass.onRender.call(this, ct, position);
36303 var cfg = this.getAutoCreate();
36305 cfg.name = this.name || this.id;
36307 if(this.inputType){
36308 cfg.type = this.inputType;
36310 this.el = ct.createChild(cfg, position);
36312 var type = this.el.dom.type;
36314 if(type == 'password'){
36317 this.el.addClass('x-form-'+type);
36320 this.el.dom.readOnly = true;
36322 if(this.tabIndex !== undefined){
36323 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36326 this.el.addClass([this.fieldClass, this.cls]);
36331 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36332 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36333 * @return {Roo.form.Field} this
36335 applyTo : function(target){
36336 this.allowDomMove = false;
36337 this.el = Roo.get(target);
36338 this.render(this.el.dom.parentNode);
36343 initValue : function(){
36344 if(this.value !== undefined){
36345 this.setValue(this.value);
36346 }else if(this.el.dom.value.length > 0){
36347 this.setValue(this.el.dom.value);
36352 * Returns true if this field has been changed since it was originally loaded and is not disabled.
36354 isDirty : function() {
36355 if(this.disabled) {
36358 return String(this.getValue()) !== String(this.originalValue);
36362 afterRender : function(){
36363 Roo.form.Field.superclass.afterRender.call(this);
36368 fireKey : function(e){
36369 //Roo.log('field ' + e.getKey());
36370 if(e.isNavKeyPress()){
36371 this.fireEvent("specialkey", this, e);
36376 * Resets the current field value to the originally loaded value and clears any validation messages
36378 reset : function(){
36379 this.setValue(this.originalValue);
36380 this.clearInvalid();
36384 initEvents : function(){
36385 // safari killled keypress - so keydown is now used..
36386 this.el.on("keydown" , this.fireKey, this);
36387 this.el.on("focus", this.onFocus, this);
36388 this.el.on("blur", this.onBlur, this);
36389 this.el.relayEvent('keyup', this);
36391 // reference to original value for reset
36392 this.originalValue = this.getValue();
36396 onFocus : function(){
36397 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36398 this.el.addClass(this.focusClass);
36400 if(!this.hasFocus){
36401 this.hasFocus = true;
36402 this.startValue = this.getValue();
36403 this.fireEvent("focus", this);
36407 beforeBlur : Roo.emptyFn,
36410 onBlur : function(){
36412 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36413 this.el.removeClass(this.focusClass);
36415 this.hasFocus = false;
36416 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
36419 var v = this.getValue();
36420 if(String(v) !== String(this.startValue)){
36421 this.fireEvent('change', this, v, this.startValue);
36423 this.fireEvent("blur", this);
36427 * Returns whether or not the field value is currently valid
36428 * @param {Boolean} preventMark True to disable marking the field invalid
36429 * @return {Boolean} True if the value is valid, else false
36431 isValid : function(preventMark){
36435 var restore = this.preventMark;
36436 this.preventMark = preventMark === true;
36437 var v = this.validateValue(this.processValue(this.getRawValue()));
36438 this.preventMark = restore;
36443 * Validates the field value
36444 * @return {Boolean} True if the value is valid, else false
36446 validate : function(){
36447 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
36448 this.clearInvalid();
36454 processValue : function(value){
36459 // Subclasses should provide the validation implementation by overriding this
36460 validateValue : function(value){
36465 * Mark this field as invalid
36466 * @param {String} msg The validation message
36468 markInvalid : function(msg){
36469 if(!this.rendered || this.preventMark){ // not rendered
36472 this.el.addClass(this.invalidClass);
36473 msg = msg || this.invalidText;
36474 switch(this.msgTarget){
36476 this.el.dom.qtip = msg;
36477 this.el.dom.qclass = 'x-form-invalid-tip';
36478 if(Roo.QuickTips){ // fix for floating editors interacting with DND
36479 Roo.QuickTips.enable();
36483 this.el.dom.title = msg;
36487 var elp = this.el.findParent('.x-form-element', 5, true);
36488 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
36489 this.errorEl.setWidth(elp.getWidth(true)-20);
36491 this.errorEl.update(msg);
36492 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
36495 if(!this.errorIcon){
36496 var elp = this.el.findParent('.x-form-element', 5, true);
36497 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36499 this.alignErrorIcon();
36500 this.errorIcon.dom.qtip = msg;
36501 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36502 this.errorIcon.show();
36503 this.on('resize', this.alignErrorIcon, this);
36506 var t = Roo.getDom(this.msgTarget);
36508 t.style.display = this.msgDisplay;
36511 this.fireEvent('invalid', this, msg);
36515 alignErrorIcon : function(){
36516 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36520 * Clear any invalid styles/messages for this field
36522 clearInvalid : function(){
36523 if(!this.rendered || this.preventMark){ // not rendered
36526 this.el.removeClass(this.invalidClass);
36527 switch(this.msgTarget){
36529 this.el.dom.qtip = '';
36532 this.el.dom.title = '';
36536 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36540 if(this.errorIcon){
36541 this.errorIcon.dom.qtip = '';
36542 this.errorIcon.hide();
36543 this.un('resize', this.alignErrorIcon, this);
36547 var t = Roo.getDom(this.msgTarget);
36549 t.style.display = 'none';
36552 this.fireEvent('valid', this);
36556 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36557 * @return {Mixed} value The field value
36559 getRawValue : function(){
36560 var v = this.el.getValue();
36561 if(v === this.emptyText){
36568 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36569 * @return {Mixed} value The field value
36571 getValue : function(){
36572 var v = this.el.getValue();
36573 if(v === this.emptyText || v === undefined){
36580 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36581 * @param {Mixed} value The value to set
36583 setRawValue : function(v){
36584 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36588 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36589 * @param {Mixed} value The value to set
36591 setValue : function(v){
36594 this.el.dom.value = (v === null || v === undefined ? '' : v);
36599 adjustSize : function(w, h){
36600 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36601 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36605 adjustWidth : function(tag, w){
36606 tag = tag.toLowerCase();
36607 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36608 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36609 if(tag == 'input'){
36612 if(tag = 'textarea'){
36615 }else if(Roo.isOpera){
36616 if(tag == 'input'){
36619 if(tag = 'textarea'){
36629 // anything other than normal should be considered experimental
36630 Roo.form.Field.msgFx = {
36632 show: function(msgEl, f){
36633 msgEl.setDisplayed('block');
36636 hide : function(msgEl, f){
36637 msgEl.setDisplayed(false).update('');
36642 show: function(msgEl, f){
36643 msgEl.slideIn('t', {stopFx:true});
36646 hide : function(msgEl, f){
36647 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36652 show: function(msgEl, f){
36653 msgEl.fixDisplay();
36654 msgEl.alignTo(f.el, 'tl-tr');
36655 msgEl.slideIn('l', {stopFx:true});
36658 hide : function(msgEl, f){
36659 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36664 * Ext JS Library 1.1.1
36665 * Copyright(c) 2006-2007, Ext JS, LLC.
36667 * Originally Released Under LGPL - original licence link has changed is not relivant.
36670 * <script type="text/javascript">
36675 * @class Roo.form.TextField
36676 * @extends Roo.form.Field
36677 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36678 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36680 * Creates a new TextField
36681 * @param {Object} config Configuration options
36683 Roo.form.TextField = function(config){
36684 Roo.form.TextField.superclass.constructor.call(this, config);
36688 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36689 * according to the default logic, but this event provides a hook for the developer to apply additional
36690 * logic at runtime to resize the field if needed.
36691 * @param {Roo.form.Field} this This text field
36692 * @param {Number} width The new field width
36698 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36700 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36704 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36708 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36712 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36716 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36720 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36722 disableKeyFilter : false,
36724 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36728 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36732 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36734 maxLength : Number.MAX_VALUE,
36736 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36738 minLengthText : "The minimum length for this field is {0}",
36740 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36742 maxLengthText : "The maximum length for this field is {0}",
36744 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36746 selectOnFocus : false,
36748 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36750 blankText : "This field is required",
36752 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36753 * If available, this function will be called only after the basic validators all return true, and will be passed the
36754 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36758 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36759 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36760 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36764 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36768 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36772 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36773 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36775 emptyClass : 'x-form-empty-field',
36778 initEvents : function(){
36779 Roo.form.TextField.superclass.initEvents.call(this);
36780 if(this.validationEvent == 'keyup'){
36781 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36782 this.el.on('keyup', this.filterValidation, this);
36784 else if(this.validationEvent !== false){
36785 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36787 if(this.selectOnFocus || this.emptyText){
36788 this.on("focus", this.preFocus, this);
36789 if(this.emptyText){
36790 this.on('blur', this.postBlur, this);
36791 this.applyEmptyText();
36794 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36795 this.el.on("keypress", this.filterKeys, this);
36798 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36799 this.el.on("click", this.autoSize, this);
36803 processValue : function(value){
36804 if(this.stripCharsRe){
36805 var newValue = value.replace(this.stripCharsRe, '');
36806 if(newValue !== value){
36807 this.setRawValue(newValue);
36814 filterValidation : function(e){
36815 if(!e.isNavKeyPress()){
36816 this.validationTask.delay(this.validationDelay);
36821 onKeyUp : function(e){
36822 if(!e.isNavKeyPress()){
36828 * Resets the current field value to the originally-loaded value and clears any validation messages.
36829 * Also adds emptyText and emptyClass if the original value was blank.
36831 reset : function(){
36832 Roo.form.TextField.superclass.reset.call(this);
36833 this.applyEmptyText();
36836 applyEmptyText : function(){
36837 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36838 this.setRawValue(this.emptyText);
36839 this.el.addClass(this.emptyClass);
36844 preFocus : function(){
36845 if(this.emptyText){
36846 if(this.el.dom.value == this.emptyText){
36847 this.setRawValue('');
36849 this.el.removeClass(this.emptyClass);
36851 if(this.selectOnFocus){
36852 this.el.dom.select();
36857 postBlur : function(){
36858 this.applyEmptyText();
36862 filterKeys : function(e){
36863 var k = e.getKey();
36864 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36867 var c = e.getCharCode(), cc = String.fromCharCode(c);
36868 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36871 if(!this.maskRe.test(cc)){
36876 setValue : function(v){
36877 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36878 this.el.removeClass(this.emptyClass);
36880 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36881 this.applyEmptyText();
36886 * Validates a value according to the field's validation rules and marks the field as invalid
36887 * if the validation fails
36888 * @param {Mixed} value The value to validate
36889 * @return {Boolean} True if the value is valid, else false
36891 validateValue : function(value){
36892 if(value.length < 1 || value === this.emptyText){ // if it's blank
36893 if(this.allowBlank){
36894 this.clearInvalid();
36897 this.markInvalid(this.blankText);
36901 if(value.length < this.minLength){
36902 this.markInvalid(String.format(this.minLengthText, this.minLength));
36905 if(value.length > this.maxLength){
36906 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36910 var vt = Roo.form.VTypes;
36911 if(!vt[this.vtype](value, this)){
36912 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36916 if(typeof this.validator == "function"){
36917 var msg = this.validator(value);
36919 this.markInvalid(msg);
36923 if(this.regex && !this.regex.test(value)){
36924 this.markInvalid(this.regexText);
36931 * Selects text in this field
36932 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36933 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36935 selectText : function(start, end){
36936 var v = this.getRawValue();
36938 start = start === undefined ? 0 : start;
36939 end = end === undefined ? v.length : end;
36940 var d = this.el.dom;
36941 if(d.setSelectionRange){
36942 d.setSelectionRange(start, end);
36943 }else if(d.createTextRange){
36944 var range = d.createTextRange();
36945 range.moveStart("character", start);
36946 range.moveEnd("character", v.length-end);
36953 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36954 * This only takes effect if grow = true, and fires the autosize event.
36956 autoSize : function(){
36957 if(!this.grow || !this.rendered){
36961 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36964 var v = el.dom.value;
36965 var d = document.createElement('div');
36966 d.appendChild(document.createTextNode(v));
36970 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36971 this.el.setWidth(w);
36972 this.fireEvent("autosize", this, w);
36976 * Ext JS Library 1.1.1
36977 * Copyright(c) 2006-2007, Ext JS, LLC.
36979 * Originally Released Under LGPL - original licence link has changed is not relivant.
36982 * <script type="text/javascript">
36986 * @class Roo.form.Hidden
36987 * @extends Roo.form.TextField
36988 * Simple Hidden element used on forms
36990 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36993 * Creates a new Hidden form element.
36994 * @param {Object} config Configuration options
36999 // easy hidden field...
37000 Roo.form.Hidden = function(config){
37001 Roo.form.Hidden.superclass.constructor.call(this, config);
37004 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37006 inputType: 'hidden',
37009 labelSeparator: '',
37011 itemCls : 'x-form-item-display-none'
37019 * Ext JS Library 1.1.1
37020 * Copyright(c) 2006-2007, Ext JS, LLC.
37022 * Originally Released Under LGPL - original licence link has changed is not relivant.
37025 * <script type="text/javascript">
37029 * @class Roo.form.TriggerField
37030 * @extends Roo.form.TextField
37031 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37032 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37033 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37034 * for which you can provide a custom implementation. For example:
37036 var trigger = new Roo.form.TriggerField();
37037 trigger.onTriggerClick = myTriggerFn;
37038 trigger.applyTo('my-field');
37041 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37042 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37043 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37044 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37046 * Create a new TriggerField.
37047 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37048 * to the base TextField)
37050 Roo.form.TriggerField = function(config){
37051 this.mimicing = false;
37052 Roo.form.TriggerField.superclass.constructor.call(this, config);
37055 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37057 * @cfg {String} triggerClass A CSS class to apply to the trigger
37060 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37061 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37063 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37065 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37069 /** @cfg {Boolean} grow @hide */
37070 /** @cfg {Number} growMin @hide */
37071 /** @cfg {Number} growMax @hide */
37077 autoSize: Roo.emptyFn,
37081 deferHeight : true,
37084 actionMode : 'wrap',
37086 onResize : function(w, h){
37087 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37088 if(typeof w == 'number'){
37089 var x = w - this.trigger.getWidth();
37090 this.el.setWidth(this.adjustWidth('input', x));
37091 this.trigger.setStyle('left', x+'px');
37096 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37099 getResizeEl : function(){
37104 getPositionEl : function(){
37109 alignErrorIcon : function(){
37110 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37114 onRender : function(ct, position){
37115 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37116 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37117 this.trigger = this.wrap.createChild(this.triggerConfig ||
37118 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37119 if(this.hideTrigger){
37120 this.trigger.setDisplayed(false);
37122 this.initTrigger();
37124 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37129 initTrigger : function(){
37130 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37131 this.trigger.addClassOnOver('x-form-trigger-over');
37132 this.trigger.addClassOnClick('x-form-trigger-click');
37136 onDestroy : function(){
37138 this.trigger.removeAllListeners();
37139 this.trigger.remove();
37142 this.wrap.remove();
37144 Roo.form.TriggerField.superclass.onDestroy.call(this);
37148 onFocus : function(){
37149 Roo.form.TriggerField.superclass.onFocus.call(this);
37150 if(!this.mimicing){
37151 this.wrap.addClass('x-trigger-wrap-focus');
37152 this.mimicing = true;
37153 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37154 if(this.monitorTab){
37155 this.el.on("keydown", this.checkTab, this);
37161 checkTab : function(e){
37162 if(e.getKey() == e.TAB){
37163 this.triggerBlur();
37168 onBlur : function(){
37173 mimicBlur : function(e, t){
37174 if(!this.wrap.contains(t) && this.validateBlur()){
37175 this.triggerBlur();
37180 triggerBlur : function(){
37181 this.mimicing = false;
37182 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37183 if(this.monitorTab){
37184 this.el.un("keydown", this.checkTab, this);
37186 this.wrap.removeClass('x-trigger-wrap-focus');
37187 Roo.form.TriggerField.superclass.onBlur.call(this);
37191 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37192 validateBlur : function(e, t){
37197 onDisable : function(){
37198 Roo.form.TriggerField.superclass.onDisable.call(this);
37200 this.wrap.addClass('x-item-disabled');
37205 onEnable : function(){
37206 Roo.form.TriggerField.superclass.onEnable.call(this);
37208 this.wrap.removeClass('x-item-disabled');
37213 onShow : function(){
37214 var ae = this.getActionEl();
37217 ae.dom.style.display = '';
37218 ae.dom.style.visibility = 'visible';
37224 onHide : function(){
37225 var ae = this.getActionEl();
37226 ae.dom.style.display = 'none';
37230 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37231 * by an implementing function.
37233 * @param {EventObject} e
37235 onTriggerClick : Roo.emptyFn
37238 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37239 // to be extended by an implementing class. For an example of implementing this class, see the custom
37240 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37241 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37242 initComponent : function(){
37243 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37245 this.triggerConfig = {
37246 tag:'span', cls:'x-form-twin-triggers', cn:[
37247 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37248 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37252 getTrigger : function(index){
37253 return this.triggers[index];
37256 initTrigger : function(){
37257 var ts = this.trigger.select('.x-form-trigger', true);
37258 this.wrap.setStyle('overflow', 'hidden');
37259 var triggerField = this;
37260 ts.each(function(t, all, index){
37261 t.hide = function(){
37262 var w = triggerField.wrap.getWidth();
37263 this.dom.style.display = 'none';
37264 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37266 t.show = function(){
37267 var w = triggerField.wrap.getWidth();
37268 this.dom.style.display = '';
37269 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37271 var triggerIndex = 'Trigger'+(index+1);
37273 if(this['hide'+triggerIndex]){
37274 t.dom.style.display = 'none';
37276 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37277 t.addClassOnOver('x-form-trigger-over');
37278 t.addClassOnClick('x-form-trigger-click');
37280 this.triggers = ts.elements;
37283 onTrigger1Click : Roo.emptyFn,
37284 onTrigger2Click : Roo.emptyFn
37287 * Ext JS Library 1.1.1
37288 * Copyright(c) 2006-2007, Ext JS, LLC.
37290 * Originally Released Under LGPL - original licence link has changed is not relivant.
37293 * <script type="text/javascript">
37297 * @class Roo.form.TextArea
37298 * @extends Roo.form.TextField
37299 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37300 * support for auto-sizing.
37302 * Creates a new TextArea
37303 * @param {Object} config Configuration options
37305 Roo.form.TextArea = function(config){
37306 Roo.form.TextArea.superclass.constructor.call(this, config);
37307 // these are provided exchanges for backwards compat
37308 // minHeight/maxHeight were replaced by growMin/growMax to be
37309 // compatible with TextField growing config values
37310 if(this.minHeight !== undefined){
37311 this.growMin = this.minHeight;
37313 if(this.maxHeight !== undefined){
37314 this.growMax = this.maxHeight;
37318 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37320 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37324 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37328 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37329 * in the field (equivalent to setting overflow: hidden, defaults to false)
37331 preventScrollbars: false,
37333 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37334 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37338 onRender : function(ct, position){
37340 this.defaultAutoCreate = {
37342 style:"width:300px;height:60px;",
37343 autocomplete: "off"
37346 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
37348 this.textSizeEl = Roo.DomHelper.append(document.body, {
37349 tag: "pre", cls: "x-form-grow-sizer"
37351 if(this.preventScrollbars){
37352 this.el.setStyle("overflow", "hidden");
37354 this.el.setHeight(this.growMin);
37358 onDestroy : function(){
37359 if(this.textSizeEl){
37360 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
37362 Roo.form.TextArea.superclass.onDestroy.call(this);
37366 onKeyUp : function(e){
37367 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
37373 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
37374 * This only takes effect if grow = true, and fires the autosize event if the height changes.
37376 autoSize : function(){
37377 if(!this.grow || !this.textSizeEl){
37381 var v = el.dom.value;
37382 var ts = this.textSizeEl;
37385 ts.appendChild(document.createTextNode(v));
37388 Roo.fly(ts).setWidth(this.el.getWidth());
37390 v = "  ";
37393 v = v.replace(/\n/g, '<p> </p>');
37395 v += " \n ";
37398 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
37399 if(h != this.lastHeight){
37400 this.lastHeight = h;
37401 this.el.setHeight(h);
37402 this.fireEvent("autosize", this, h);
37407 * Ext JS Library 1.1.1
37408 * Copyright(c) 2006-2007, Ext JS, LLC.
37410 * Originally Released Under LGPL - original licence link has changed is not relivant.
37413 * <script type="text/javascript">
37418 * @class Roo.form.NumberField
37419 * @extends Roo.form.TextField
37420 * Numeric text field that provides automatic keystroke filtering and numeric validation.
37422 * Creates a new NumberField
37423 * @param {Object} config Configuration options
37425 Roo.form.NumberField = function(config){
37426 Roo.form.NumberField.superclass.constructor.call(this, config);
37429 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
37431 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
37433 fieldClass: "x-form-field x-form-num-field",
37435 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
37437 allowDecimals : true,
37439 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
37441 decimalSeparator : ".",
37443 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37445 decimalPrecision : 2,
37447 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37449 allowNegative : true,
37451 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
37453 minValue : Number.NEGATIVE_INFINITY,
37455 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
37457 maxValue : Number.MAX_VALUE,
37459 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
37461 minText : "The minimum value for this field is {0}",
37463 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
37465 maxText : "The maximum value for this field is {0}",
37467 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
37468 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
37470 nanText : "{0} is not a valid number",
37473 initEvents : function(){
37474 Roo.form.NumberField.superclass.initEvents.call(this);
37475 var allowed = "0123456789";
37476 if(this.allowDecimals){
37477 allowed += this.decimalSeparator;
37479 if(this.allowNegative){
37482 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
37483 var keyPress = function(e){
37484 var k = e.getKey();
37485 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
37488 var c = e.getCharCode();
37489 if(allowed.indexOf(String.fromCharCode(c)) === -1){
37493 this.el.on("keypress", keyPress, this);
37497 validateValue : function(value){
37498 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37501 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37504 var num = this.parseValue(value);
37506 this.markInvalid(String.format(this.nanText, value));
37509 if(num < this.minValue){
37510 this.markInvalid(String.format(this.minText, this.minValue));
37513 if(num > this.maxValue){
37514 this.markInvalid(String.format(this.maxText, this.maxValue));
37520 getValue : function(){
37521 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37525 parseValue : function(value){
37526 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37527 return isNaN(value) ? '' : value;
37531 fixPrecision : function(value){
37532 var nan = isNaN(value);
37533 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37534 return nan ? '' : value;
37536 return parseFloat(value).toFixed(this.decimalPrecision);
37539 setValue : function(v){
37540 v = this.fixPrecision(v);
37541 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37545 decimalPrecisionFcn : function(v){
37546 return Math.floor(v);
37549 beforeBlur : function(){
37550 var v = this.parseValue(this.getRawValue());
37557 * Ext JS Library 1.1.1
37558 * Copyright(c) 2006-2007, Ext JS, LLC.
37560 * Originally Released Under LGPL - original licence link has changed is not relivant.
37563 * <script type="text/javascript">
37567 * @class Roo.form.DateField
37568 * @extends Roo.form.TriggerField
37569 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37571 * Create a new DateField
37572 * @param {Object} config
37574 Roo.form.DateField = function(config){
37575 Roo.form.DateField.superclass.constructor.call(this, config);
37581 * Fires when a date is selected
37582 * @param {Roo.form.DateField} combo This combo box
37583 * @param {Date} date The date selected
37590 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37591 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37592 this.ddMatch = null;
37593 if(this.disabledDates){
37594 var dd = this.disabledDates;
37596 for(var i = 0; i < dd.length; i++){
37598 if(i != dd.length-1) re += "|";
37600 this.ddMatch = new RegExp(re + ")");
37604 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37606 * @cfg {String} format
37607 * The default date format string which can be overriden for localization support. The format must be
37608 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37612 * @cfg {String} altFormats
37613 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37614 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37616 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37618 * @cfg {Array} disabledDays
37619 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37621 disabledDays : null,
37623 * @cfg {String} disabledDaysText
37624 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37626 disabledDaysText : "Disabled",
37628 * @cfg {Array} disabledDates
37629 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37630 * expression so they are very powerful. Some examples:
37632 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37633 * <li>["03/08", "09/16"] would disable those days for every year</li>
37634 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37635 * <li>["03/../2006"] would disable every day in March 2006</li>
37636 * <li>["^03"] would disable every day in every March</li>
37638 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37639 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37641 disabledDates : null,
37643 * @cfg {String} disabledDatesText
37644 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37646 disabledDatesText : "Disabled",
37648 * @cfg {Date/String} minValue
37649 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37650 * valid format (defaults to null).
37654 * @cfg {Date/String} maxValue
37655 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37656 * valid format (defaults to null).
37660 * @cfg {String} minText
37661 * The error text to display when the date in the cell is before minValue (defaults to
37662 * 'The date in this field must be after {minValue}').
37664 minText : "The date in this field must be equal to or after {0}",
37666 * @cfg {String} maxText
37667 * The error text to display when the date in the cell is after maxValue (defaults to
37668 * 'The date in this field must be before {maxValue}').
37670 maxText : "The date in this field must be equal to or before {0}",
37672 * @cfg {String} invalidText
37673 * The error text to display when the date in the field is invalid (defaults to
37674 * '{value} is not a valid date - it must be in the format {format}').
37676 invalidText : "{0} is not a valid date - it must be in the format {1}",
37678 * @cfg {String} triggerClass
37679 * An additional CSS class used to style the trigger button. The trigger will always get the
37680 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37681 * which displays a calendar icon).
37683 triggerClass : 'x-form-date-trigger',
37687 * @cfg {Boolean} useIso
37688 * if enabled, then the date field will use a hidden field to store the
37689 * real value as iso formated date. default (false)
37693 * @cfg {String/Object} autoCreate
37694 * A DomHelper element spec, or true for a default element spec (defaults to
37695 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37698 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37701 hiddenField: false,
37703 onRender : function(ct, position)
37705 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37707 this.el.dom.removeAttribute('name');
37708 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37710 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
37711 // prevent input submission
37712 this.hiddenName = this.name;
37719 validateValue : function(value)
37721 value = this.formatDate(value);
37722 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37723 Roo.log('super failed');
37726 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37729 var svalue = value;
37730 value = this.parseDate(value);
37732 Roo.log('parse date failed' + svalue);
37733 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37736 var time = value.getTime();
37737 if(this.minValue && time < this.minValue.getTime()){
37738 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37741 if(this.maxValue && time > this.maxValue.getTime()){
37742 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37745 if(this.disabledDays){
37746 var day = value.getDay();
37747 for(var i = 0; i < this.disabledDays.length; i++) {
37748 if(day === this.disabledDays[i]){
37749 this.markInvalid(this.disabledDaysText);
37754 var fvalue = this.formatDate(value);
37755 if(this.ddMatch && this.ddMatch.test(fvalue)){
37756 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37763 // Provides logic to override the default TriggerField.validateBlur which just returns true
37764 validateBlur : function(){
37765 return !this.menu || !this.menu.isVisible();
37769 * Returns the current date value of the date field.
37770 * @return {Date} The date value
37772 getValue : function(){
37774 return this.hiddenField ?
37775 this.hiddenField.value :
37776 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37780 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37781 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37782 * (the default format used is "m/d/y").
37785 //All of these calls set the same date value (May 4, 2006)
37787 //Pass a date object:
37788 var dt = new Date('5/4/06');
37789 dateField.setValue(dt);
37791 //Pass a date string (default format):
37792 dateField.setValue('5/4/06');
37794 //Pass a date string (custom format):
37795 dateField.format = 'Y-m-d';
37796 dateField.setValue('2006-5-4');
37798 * @param {String/Date} date The date or valid date string
37800 setValue : function(date){
37801 if (this.hiddenField) {
37802 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37804 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37805 // make sure the value field is always stored as a date..
37806 this.value = this.parseDate(date);
37812 parseDate : function(value){
37813 if(!value || value instanceof Date){
37816 var v = Date.parseDate(value, this.format);
37817 if (!v && this.useIso) {
37818 v = Date.parseDate(value, 'Y-m-d');
37820 if(!v && this.altFormats){
37821 if(!this.altFormatsArray){
37822 this.altFormatsArray = this.altFormats.split("|");
37824 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37825 v = Date.parseDate(value, this.altFormatsArray[i]);
37832 formatDate : function(date, fmt){
37833 return (!date || !(date instanceof Date)) ?
37834 date : date.dateFormat(fmt || this.format);
37839 select: function(m, d){
37842 this.fireEvent('select', this, d);
37844 show : function(){ // retain focus styling
37848 this.focus.defer(10, this);
37849 var ml = this.menuListeners;
37850 this.menu.un("select", ml.select, this);
37851 this.menu.un("show", ml.show, this);
37852 this.menu.un("hide", ml.hide, this);
37857 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37858 onTriggerClick : function(){
37862 if(this.menu == null){
37863 this.menu = new Roo.menu.DateMenu();
37865 Roo.apply(this.menu.picker, {
37866 showClear: this.allowBlank,
37867 minDate : this.minValue,
37868 maxDate : this.maxValue,
37869 disabledDatesRE : this.ddMatch,
37870 disabledDatesText : this.disabledDatesText,
37871 disabledDays : this.disabledDays,
37872 disabledDaysText : this.disabledDaysText,
37873 format : this.useIso ? 'Y-m-d' : this.format,
37874 minText : String.format(this.minText, this.formatDate(this.minValue)),
37875 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37877 this.menu.on(Roo.apply({}, this.menuListeners, {
37880 this.menu.picker.setValue(this.getValue() || new Date());
37881 this.menu.show(this.el, "tl-bl?");
37884 beforeBlur : function(){
37885 var v = this.parseDate(this.getRawValue());
37891 /** @cfg {Boolean} grow @hide */
37892 /** @cfg {Number} growMin @hide */
37893 /** @cfg {Number} growMax @hide */
37900 * Ext JS Library 1.1.1
37901 * Copyright(c) 2006-2007, Ext JS, LLC.
37903 * Originally Released Under LGPL - original licence link has changed is not relivant.
37906 * <script type="text/javascript">
37910 * @class Roo.form.MonthField
37911 * @extends Roo.form.TriggerField
37912 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37914 * Create a new MonthField
37915 * @param {Object} config
37917 Roo.form.MonthField = function(config){
37919 Roo.form.MonthField.superclass.constructor.call(this, config);
37925 * Fires when a date is selected
37926 * @param {Roo.form.MonthFieeld} combo This combo box
37927 * @param {Date} date The date selected
37934 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37935 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37936 this.ddMatch = null;
37937 if(this.disabledDates){
37938 var dd = this.disabledDates;
37940 for(var i = 0; i < dd.length; i++){
37942 if(i != dd.length-1) re += "|";
37944 this.ddMatch = new RegExp(re + ")");
37948 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
37950 * @cfg {String} format
37951 * The default date format string which can be overriden for localization support. The format must be
37952 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37956 * @cfg {String} altFormats
37957 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37958 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37960 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
37962 * @cfg {Array} disabledDays
37963 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37965 disabledDays : [0,1,2,3,4,5,6],
37967 * @cfg {String} disabledDaysText
37968 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37970 disabledDaysText : "Disabled",
37972 * @cfg {Array} disabledDates
37973 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37974 * expression so they are very powerful. Some examples:
37976 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37977 * <li>["03/08", "09/16"] would disable those days for every year</li>
37978 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37979 * <li>["03/../2006"] would disable every day in March 2006</li>
37980 * <li>["^03"] would disable every day in every March</li>
37982 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37983 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37985 disabledDates : null,
37987 * @cfg {String} disabledDatesText
37988 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37990 disabledDatesText : "Disabled",
37992 * @cfg {Date/String} minValue
37993 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37994 * valid format (defaults to null).
37998 * @cfg {Date/String} maxValue
37999 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38000 * valid format (defaults to null).
38004 * @cfg {String} minText
38005 * The error text to display when the date in the cell is before minValue (defaults to
38006 * 'The date in this field must be after {minValue}').
38008 minText : "The date in this field must be equal to or after {0}",
38010 * @cfg {String} maxTextf
38011 * The error text to display when the date in the cell is after maxValue (defaults to
38012 * 'The date in this field must be before {maxValue}').
38014 maxText : "The date in this field must be equal to or before {0}",
38016 * @cfg {String} invalidText
38017 * The error text to display when the date in the field is invalid (defaults to
38018 * '{value} is not a valid date - it must be in the format {format}').
38020 invalidText : "{0} is not a valid date - it must be in the format {1}",
38022 * @cfg {String} triggerClass
38023 * An additional CSS class used to style the trigger button. The trigger will always get the
38024 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38025 * which displays a calendar icon).
38027 triggerClass : 'x-form-date-trigger',
38031 * @cfg {Boolean} useIso
38032 * if enabled, then the date field will use a hidden field to store the
38033 * real value as iso formated date. default (true)
38037 * @cfg {String/Object} autoCreate
38038 * A DomHelper element spec, or true for a default element spec (defaults to
38039 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38042 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38045 hiddenField: false,
38047 hideMonthPicker : false,
38049 onRender : function(ct, position)
38051 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38053 this.el.dom.removeAttribute('name');
38054 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38056 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38057 // prevent input submission
38058 this.hiddenName = this.name;
38065 validateValue : function(value)
38067 value = this.formatDate(value);
38068 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38071 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38074 var svalue = value;
38075 value = this.parseDate(value);
38077 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38080 var time = value.getTime();
38081 if(this.minValue && time < this.minValue.getTime()){
38082 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38085 if(this.maxValue && time > this.maxValue.getTime()){
38086 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38089 /*if(this.disabledDays){
38090 var day = value.getDay();
38091 for(var i = 0; i < this.disabledDays.length; i++) {
38092 if(day === this.disabledDays[i]){
38093 this.markInvalid(this.disabledDaysText);
38099 var fvalue = this.formatDate(value);
38100 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38101 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38109 // Provides logic to override the default TriggerField.validateBlur which just returns true
38110 validateBlur : function(){
38111 return !this.menu || !this.menu.isVisible();
38115 * Returns the current date value of the date field.
38116 * @return {Date} The date value
38118 getValue : function(){
38122 return this.hiddenField ?
38123 this.hiddenField.value :
38124 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38128 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38129 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38130 * (the default format used is "m/d/y").
38133 //All of these calls set the same date value (May 4, 2006)
38135 //Pass a date object:
38136 var dt = new Date('5/4/06');
38137 monthField.setValue(dt);
38139 //Pass a date string (default format):
38140 monthField.setValue('5/4/06');
38142 //Pass a date string (custom format):
38143 monthField.format = 'Y-m-d';
38144 monthField.setValue('2006-5-4');
38146 * @param {String/Date} date The date or valid date string
38148 setValue : function(date){
38149 Roo.log('month setValue' + date);
38150 // can only be first of month..
38152 var val = this.parseDate(date);
38154 if (this.hiddenField) {
38155 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38157 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38158 this.value = this.parseDate(date);
38162 parseDate : function(value){
38163 if(!value || value instanceof Date){
38164 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38167 var v = Date.parseDate(value, this.format);
38168 if (!v && this.useIso) {
38169 v = Date.parseDate(value, 'Y-m-d');
38173 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38177 if(!v && this.altFormats){
38178 if(!this.altFormatsArray){
38179 this.altFormatsArray = this.altFormats.split("|");
38181 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38182 v = Date.parseDate(value, this.altFormatsArray[i]);
38189 formatDate : function(date, fmt){
38190 return (!date || !(date instanceof Date)) ?
38191 date : date.dateFormat(fmt || this.format);
38196 select: function(m, d){
38198 this.fireEvent('select', this, d);
38200 show : function(){ // retain focus styling
38204 this.focus.defer(10, this);
38205 var ml = this.menuListeners;
38206 this.menu.un("select", ml.select, this);
38207 this.menu.un("show", ml.show, this);
38208 this.menu.un("hide", ml.hide, this);
38212 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38213 onTriggerClick : function(){
38217 if(this.menu == null){
38218 this.menu = new Roo.menu.DateMenu();
38222 Roo.apply(this.menu.picker, {
38224 showClear: this.allowBlank,
38225 minDate : this.minValue,
38226 maxDate : this.maxValue,
38227 disabledDatesRE : this.ddMatch,
38228 disabledDatesText : this.disabledDatesText,
38230 format : this.useIso ? 'Y-m-d' : this.format,
38231 minText : String.format(this.minText, this.formatDate(this.minValue)),
38232 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38235 this.menu.on(Roo.apply({}, this.menuListeners, {
38243 // hide month picker get's called when we called by 'before hide';
38245 var ignorehide = true;
38246 p.hideMonthPicker = function(disableAnim){
38250 if(this.monthPicker){
38251 Roo.log("hideMonthPicker called");
38252 if(disableAnim === true){
38253 this.monthPicker.hide();
38255 this.monthPicker.slideOut('t', {duration:.2});
38256 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38257 p.fireEvent("select", this, this.value);
38263 Roo.log('picker set value');
38264 Roo.log(this.getValue());
38265 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38266 m.show(this.el, 'tl-bl?');
38267 ignorehide = false;
38268 // this will trigger hideMonthPicker..
38271 // hidden the day picker
38272 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38278 p.showMonthPicker.defer(100, p);
38284 beforeBlur : function(){
38285 var v = this.parseDate(this.getRawValue());
38291 /** @cfg {Boolean} grow @hide */
38292 /** @cfg {Number} growMin @hide */
38293 /** @cfg {Number} growMax @hide */
38300 * Ext JS Library 1.1.1
38301 * Copyright(c) 2006-2007, Ext JS, LLC.
38303 * Originally Released Under LGPL - original licence link has changed is not relivant.
38306 * <script type="text/javascript">
38311 * @class Roo.form.ComboBox
38312 * @extends Roo.form.TriggerField
38313 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38315 * Create a new ComboBox.
38316 * @param {Object} config Configuration options
38318 Roo.form.ComboBox = function(config){
38319 Roo.form.ComboBox.superclass.constructor.call(this, config);
38323 * Fires when the dropdown list is expanded
38324 * @param {Roo.form.ComboBox} combo This combo box
38329 * Fires when the dropdown list is collapsed
38330 * @param {Roo.form.ComboBox} combo This combo box
38334 * @event beforeselect
38335 * Fires before a list item is selected. Return false to cancel the selection.
38336 * @param {Roo.form.ComboBox} combo This combo box
38337 * @param {Roo.data.Record} record The data record returned from the underlying store
38338 * @param {Number} index The index of the selected item in the dropdown list
38340 'beforeselect' : true,
38343 * Fires when a list item is selected
38344 * @param {Roo.form.ComboBox} combo This combo box
38345 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
38346 * @param {Number} index The index of the selected item in the dropdown list
38350 * @event beforequery
38351 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
38352 * The event object passed has these properties:
38353 * @param {Roo.form.ComboBox} combo This combo box
38354 * @param {String} query The query
38355 * @param {Boolean} forceAll true to force "all" query
38356 * @param {Boolean} cancel true to cancel the query
38357 * @param {Object} e The query event object
38359 'beforequery': true,
38362 * Fires when the 'add' icon is pressed (add a listener to enable add button)
38363 * @param {Roo.form.ComboBox} combo This combo box
38368 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
38369 * @param {Roo.form.ComboBox} combo This combo box
38370 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
38376 if(this.transform){
38377 this.allowDomMove = false;
38378 var s = Roo.getDom(this.transform);
38379 if(!this.hiddenName){
38380 this.hiddenName = s.name;
38383 this.mode = 'local';
38384 var d = [], opts = s.options;
38385 for(var i = 0, len = opts.length;i < len; i++){
38387 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
38389 this.value = value;
38391 d.push([value, o.text]);
38393 this.store = new Roo.data.SimpleStore({
38395 fields: ['value', 'text'],
38398 this.valueField = 'value';
38399 this.displayField = 'text';
38401 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
38402 if(!this.lazyRender){
38403 this.target = true;
38404 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
38405 s.parentNode.removeChild(s); // remove it
38406 this.render(this.el.parentNode);
38408 s.parentNode.removeChild(s); // remove it
38413 this.store = Roo.factory(this.store, Roo.data);
38416 this.selectedIndex = -1;
38417 if(this.mode == 'local'){
38418 if(config.queryDelay === undefined){
38419 this.queryDelay = 10;
38421 if(config.minChars === undefined){
38427 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
38429 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
38432 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
38433 * rendering into an Roo.Editor, defaults to false)
38436 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
38437 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
38440 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
38443 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
38444 * the dropdown list (defaults to undefined, with no header element)
38448 * @cfg {String/Roo.Template} tpl The template to use to render the output
38452 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
38454 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
38456 listWidth: undefined,
38458 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
38459 * mode = 'remote' or 'text' if mode = 'local')
38461 displayField: undefined,
38463 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
38464 * mode = 'remote' or 'value' if mode = 'local').
38465 * Note: use of a valueField requires the user make a selection
38466 * in order for a value to be mapped.
38468 valueField: undefined,
38472 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
38473 * field's data value (defaults to the underlying DOM element's name)
38475 hiddenName: undefined,
38477 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
38481 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
38483 selectedClass: 'x-combo-selected',
38485 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38486 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
38487 * which displays a downward arrow icon).
38489 triggerClass : 'x-form-arrow-trigger',
38491 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
38495 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
38496 * anchor positions (defaults to 'tl-bl')
38498 listAlign: 'tl-bl?',
38500 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
38504 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
38505 * query specified by the allQuery config option (defaults to 'query')
38507 triggerAction: 'query',
38509 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
38510 * (defaults to 4, does not apply if editable = false)
38514 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
38515 * delay (typeAheadDelay) if it matches a known value (defaults to false)
38519 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
38520 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
38524 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
38525 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
38529 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
38530 * when editable = true (defaults to false)
38532 selectOnFocus:false,
38534 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
38536 queryParam: 'query',
38538 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
38539 * when mode = 'remote' (defaults to 'Loading...')
38541 loadingText: 'Loading...',
38543 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
38547 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
38551 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
38552 * traditional select (defaults to true)
38556 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
38560 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
38564 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
38565 * listWidth has a higher value)
38569 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
38570 * allow the user to set arbitrary text into the field (defaults to false)
38572 forceSelection:false,
38574 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
38575 * if typeAhead = true (defaults to 250)
38577 typeAheadDelay : 250,
38579 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
38580 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
38582 valueNotFoundText : undefined,
38584 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
38586 blockFocus : false,
38589 * @cfg {Boolean} disableClear Disable showing of clear button.
38591 disableClear : false,
38593 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
38595 alwaysQuery : false,
38601 // element that contains real text value.. (when hidden is used..)
38604 onRender : function(ct, position){
38605 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
38606 if(this.hiddenName){
38607 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
38609 this.hiddenField.value =
38610 this.hiddenValue !== undefined ? this.hiddenValue :
38611 this.value !== undefined ? this.value : '';
38613 // prevent input submission
38614 this.el.dom.removeAttribute('name');
38619 this.el.dom.setAttribute('autocomplete', 'off');
38622 var cls = 'x-combo-list';
38624 this.list = new Roo.Layer({
38625 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38628 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
38629 this.list.setWidth(lw);
38630 this.list.swallowEvent('mousewheel');
38631 this.assetHeight = 0;
38634 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38635 this.assetHeight += this.header.getHeight();
38638 this.innerList = this.list.createChild({cls:cls+'-inner'});
38639 this.innerList.on('mouseover', this.onViewOver, this);
38640 this.innerList.on('mousemove', this.onViewMove, this);
38641 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38643 if(this.allowBlank && !this.pageSize && !this.disableClear){
38644 this.footer = this.list.createChild({cls:cls+'-ft'});
38645 this.pageTb = new Roo.Toolbar(this.footer);
38649 this.footer = this.list.createChild({cls:cls+'-ft'});
38650 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38651 {pageSize: this.pageSize});
38655 if (this.pageTb && this.allowBlank && !this.disableClear) {
38657 this.pageTb.add(new Roo.Toolbar.Fill(), {
38658 cls: 'x-btn-icon x-btn-clear',
38660 handler: function()
38663 _this.clearValue();
38664 _this.onSelect(false, -1);
38669 this.assetHeight += this.footer.getHeight();
38674 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
38677 this.view = new Roo.View(this.innerList, this.tpl, {
38678 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38681 this.view.on('click', this.onViewClick, this);
38683 this.store.on('beforeload', this.onBeforeLoad, this);
38684 this.store.on('load', this.onLoad, this);
38685 this.store.on('loadexception', this.onLoadException, this);
38687 if(this.resizable){
38688 this.resizer = new Roo.Resizable(this.list, {
38689 pinned:true, handles:'se'
38691 this.resizer.on('resize', function(r, w, h){
38692 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38693 this.listWidth = w;
38694 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38695 this.restrictHeight();
38697 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38699 if(!this.editable){
38700 this.editable = true;
38701 this.setEditable(false);
38705 if (typeof(this.events.add.listeners) != 'undefined') {
38707 this.addicon = this.wrap.createChild(
38708 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38710 this.addicon.on('click', function(e) {
38711 this.fireEvent('add', this);
38714 if (typeof(this.events.edit.listeners) != 'undefined') {
38716 this.editicon = this.wrap.createChild(
38717 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38718 if (this.addicon) {
38719 this.editicon.setStyle('margin-left', '40px');
38721 this.editicon.on('click', function(e) {
38723 // we fire even if inothing is selected..
38724 this.fireEvent('edit', this, this.lastData );
38734 initEvents : function(){
38735 Roo.form.ComboBox.superclass.initEvents.call(this);
38737 this.keyNav = new Roo.KeyNav(this.el, {
38738 "up" : function(e){
38739 this.inKeyMode = true;
38743 "down" : function(e){
38744 if(!this.isExpanded()){
38745 this.onTriggerClick();
38747 this.inKeyMode = true;
38752 "enter" : function(e){
38753 this.onViewClick();
38757 "esc" : function(e){
38761 "tab" : function(e){
38762 this.onViewClick(false);
38763 this.fireEvent("specialkey", this, e);
38769 doRelay : function(foo, bar, hname){
38770 if(hname == 'down' || this.scope.isExpanded()){
38771 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38778 this.queryDelay = Math.max(this.queryDelay || 10,
38779 this.mode == 'local' ? 10 : 250);
38780 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38781 if(this.typeAhead){
38782 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38784 if(this.editable !== false){
38785 this.el.on("keyup", this.onKeyUp, this);
38787 if(this.forceSelection){
38788 this.on('blur', this.doForce, this);
38792 onDestroy : function(){
38794 this.view.setStore(null);
38795 this.view.el.removeAllListeners();
38796 this.view.el.remove();
38797 this.view.purgeListeners();
38800 this.list.destroy();
38803 this.store.un('beforeload', this.onBeforeLoad, this);
38804 this.store.un('load', this.onLoad, this);
38805 this.store.un('loadexception', this.onLoadException, this);
38807 Roo.form.ComboBox.superclass.onDestroy.call(this);
38811 fireKey : function(e){
38812 if(e.isNavKeyPress() && !this.list.isVisible()){
38813 this.fireEvent("specialkey", this, e);
38818 onResize: function(w, h){
38819 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
38821 if(typeof w != 'number'){
38822 // we do not handle it!?!?
38825 var tw = this.trigger.getWidth();
38826 tw += this.addicon ? this.addicon.getWidth() : 0;
38827 tw += this.editicon ? this.editicon.getWidth() : 0;
38829 this.el.setWidth( this.adjustWidth('input', x));
38831 this.trigger.setStyle('left', x+'px');
38833 if(this.list && this.listWidth === undefined){
38834 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38835 this.list.setWidth(lw);
38836 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38844 * Allow or prevent the user from directly editing the field text. If false is passed,
38845 * the user will only be able to select from the items defined in the dropdown list. This method
38846 * is the runtime equivalent of setting the 'editable' config option at config time.
38847 * @param {Boolean} value True to allow the user to directly edit the field text
38849 setEditable : function(value){
38850 if(value == this.editable){
38853 this.editable = value;
38855 this.el.dom.setAttribute('readOnly', true);
38856 this.el.on('mousedown', this.onTriggerClick, this);
38857 this.el.addClass('x-combo-noedit');
38859 this.el.dom.setAttribute('readOnly', false);
38860 this.el.un('mousedown', this.onTriggerClick, this);
38861 this.el.removeClass('x-combo-noedit');
38866 onBeforeLoad : function(){
38867 if(!this.hasFocus){
38870 this.innerList.update(this.loadingText ?
38871 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
38872 this.restrictHeight();
38873 this.selectedIndex = -1;
38877 onLoad : function(){
38878 if(!this.hasFocus){
38881 if(this.store.getCount() > 0){
38883 this.restrictHeight();
38884 if(this.lastQuery == this.allQuery){
38886 this.el.dom.select();
38888 if(!this.selectByValue(this.value, true)){
38889 this.select(0, true);
38893 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38894 this.taTask.delay(this.typeAheadDelay);
38898 this.onEmptyResults();
38903 onLoadException : function()
38906 Roo.log(this.store.reader.jsonData);
38907 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
38908 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
38914 onTypeAhead : function(){
38915 if(this.store.getCount() > 0){
38916 var r = this.store.getAt(0);
38917 var newValue = r.data[this.displayField];
38918 var len = newValue.length;
38919 var selStart = this.getRawValue().length;
38920 if(selStart != len){
38921 this.setRawValue(newValue);
38922 this.selectText(selStart, newValue.length);
38928 onSelect : function(record, index){
38929 if(this.fireEvent('beforeselect', this, record, index) !== false){
38930 this.setFromData(index > -1 ? record.data : false);
38932 this.fireEvent('select', this, record, index);
38937 * Returns the currently selected field value or empty string if no value is set.
38938 * @return {String} value The selected value
38940 getValue : function(){
38941 if(this.valueField){
38942 return typeof this.value != 'undefined' ? this.value : '';
38944 return Roo.form.ComboBox.superclass.getValue.call(this);
38949 * Clears any text/value currently set in the field
38951 clearValue : function(){
38952 if(this.hiddenField){
38953 this.hiddenField.value = '';
38956 this.setRawValue('');
38957 this.lastSelectionText = '';
38958 this.applyEmptyText();
38962 * Sets the specified value into the field. If the value finds a match, the corresponding record text
38963 * will be displayed in the field. If the value does not match the data value of an existing item,
38964 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
38965 * Otherwise the field will be blank (although the value will still be set).
38966 * @param {String} value The value to match
38968 setValue : function(v){
38970 if(this.valueField){
38971 var r = this.findRecord(this.valueField, v);
38973 text = r.data[this.displayField];
38974 }else if(this.valueNotFoundText !== undefined){
38975 text = this.valueNotFoundText;
38978 this.lastSelectionText = text;
38979 if(this.hiddenField){
38980 this.hiddenField.value = v;
38982 Roo.form.ComboBox.superclass.setValue.call(this, text);
38986 * @property {Object} the last set data for the element
38991 * Sets the value of the field based on a object which is related to the record format for the store.
38992 * @param {Object} value the value to set as. or false on reset?
38994 setFromData : function(o){
38995 var dv = ''; // display value
38996 var vv = ''; // value value..
38998 if (this.displayField) {
38999 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39001 // this is an error condition!!!
39002 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39005 if(this.valueField){
39006 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39008 if(this.hiddenField){
39009 this.hiddenField.value = vv;
39011 this.lastSelectionText = dv;
39012 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39016 // no hidden field.. - we store the value in 'value', but still display
39017 // display field!!!!
39018 this.lastSelectionText = dv;
39019 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39025 reset : function(){
39026 // overridden so that last data is reset..
39027 this.setValue(this.originalValue);
39028 this.clearInvalid();
39029 this.lastData = false;
39031 this.view.clearSelections();
39035 findRecord : function(prop, value){
39037 if(this.store.getCount() > 0){
39038 this.store.each(function(r){
39039 if(r.data[prop] == value){
39049 getName: function()
39051 // returns hidden if it's set..
39052 if (!this.rendered) {return ''};
39053 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39057 onViewMove : function(e, t){
39058 this.inKeyMode = false;
39062 onViewOver : function(e, t){
39063 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39066 var item = this.view.findItemFromChild(t);
39068 var index = this.view.indexOf(item);
39069 this.select(index, false);
39074 onViewClick : function(doFocus)
39076 var index = this.view.getSelectedIndexes()[0];
39077 var r = this.store.getAt(index);
39079 this.onSelect(r, index);
39081 if(doFocus !== false && !this.blockFocus){
39087 restrictHeight : function(){
39088 this.innerList.dom.style.height = '';
39089 var inner = this.innerList.dom;
39090 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39091 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39092 this.list.beginUpdate();
39093 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39094 this.list.alignTo(this.el, this.listAlign);
39095 this.list.endUpdate();
39099 onEmptyResults : function(){
39104 * Returns true if the dropdown list is expanded, else false.
39106 isExpanded : function(){
39107 return this.list.isVisible();
39111 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39112 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39113 * @param {String} value The data value of the item to select
39114 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39115 * selected item if it is not currently in view (defaults to true)
39116 * @return {Boolean} True if the value matched an item in the list, else false
39118 selectByValue : function(v, scrollIntoView){
39119 if(v !== undefined && v !== null){
39120 var r = this.findRecord(this.valueField || this.displayField, v);
39122 this.select(this.store.indexOf(r), scrollIntoView);
39130 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39131 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39132 * @param {Number} index The zero-based index of the list item to select
39133 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39134 * selected item if it is not currently in view (defaults to true)
39136 select : function(index, scrollIntoView){
39137 this.selectedIndex = index;
39138 this.view.select(index);
39139 if(scrollIntoView !== false){
39140 var el = this.view.getNode(index);
39142 this.innerList.scrollChildIntoView(el, false);
39148 selectNext : function(){
39149 var ct = this.store.getCount();
39151 if(this.selectedIndex == -1){
39153 }else if(this.selectedIndex < ct-1){
39154 this.select(this.selectedIndex+1);
39160 selectPrev : function(){
39161 var ct = this.store.getCount();
39163 if(this.selectedIndex == -1){
39165 }else if(this.selectedIndex != 0){
39166 this.select(this.selectedIndex-1);
39172 onKeyUp : function(e){
39173 if(this.editable !== false && !e.isSpecialKey()){
39174 this.lastKey = e.getKey();
39175 this.dqTask.delay(this.queryDelay);
39180 validateBlur : function(){
39181 return !this.list || !this.list.isVisible();
39185 initQuery : function(){
39186 this.doQuery(this.getRawValue());
39190 doForce : function(){
39191 if(this.el.dom.value.length > 0){
39192 this.el.dom.value =
39193 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39194 this.applyEmptyText();
39199 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39200 * query allowing the query action to be canceled if needed.
39201 * @param {String} query The SQL query to execute
39202 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39203 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39204 * saved in the current store (defaults to false)
39206 doQuery : function(q, forceAll){
39207 if(q === undefined || q === null){
39212 forceAll: forceAll,
39216 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39220 forceAll = qe.forceAll;
39221 if(forceAll === true || (q.length >= this.minChars)){
39222 if(this.lastQuery != q || this.alwaysQuery){
39223 this.lastQuery = q;
39224 if(this.mode == 'local'){
39225 this.selectedIndex = -1;
39227 this.store.clearFilter();
39229 this.store.filter(this.displayField, q);
39233 this.store.baseParams[this.queryParam] = q;
39235 params: this.getParams(q)
39240 this.selectedIndex = -1;
39247 getParams : function(q){
39249 //p[this.queryParam] = q;
39252 p.limit = this.pageSize;
39258 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39260 collapse : function(){
39261 if(!this.isExpanded()){
39265 Roo.get(document).un('mousedown', this.collapseIf, this);
39266 Roo.get(document).un('mousewheel', this.collapseIf, this);
39267 if (!this.editable) {
39268 Roo.get(document).un('keydown', this.listKeyPress, this);
39270 this.fireEvent('collapse', this);
39274 collapseIf : function(e){
39275 if(!e.within(this.wrap) && !e.within(this.list)){
39281 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39283 expand : function(){
39284 if(this.isExpanded() || !this.hasFocus){
39287 this.list.alignTo(this.el, this.listAlign);
39289 Roo.get(document).on('mousedown', this.collapseIf, this);
39290 Roo.get(document).on('mousewheel', this.collapseIf, this);
39291 if (!this.editable) {
39292 Roo.get(document).on('keydown', this.listKeyPress, this);
39295 this.fireEvent('expand', this);
39299 // Implements the default empty TriggerField.onTriggerClick function
39300 onTriggerClick : function(){
39304 if(this.isExpanded()){
39306 if (!this.blockFocus) {
39311 this.hasFocus = true;
39312 if(this.triggerAction == 'all') {
39313 this.doQuery(this.allQuery, true);
39315 this.doQuery(this.getRawValue());
39317 if (!this.blockFocus) {
39322 listKeyPress : function(e)
39324 //Roo.log('listkeypress');
39325 // scroll to first matching element based on key pres..
39326 if (e.isSpecialKey()) {
39329 var k = String.fromCharCode(e.getKey()).toUpperCase();
39332 var csel = this.view.getSelectedNodes();
39333 var cselitem = false;
39335 var ix = this.view.indexOf(csel[0]);
39336 cselitem = this.store.getAt(ix);
39337 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39343 this.store.each(function(v) {
39345 // start at existing selection.
39346 if (cselitem.id == v.id) {
39352 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39353 match = this.store.indexOf(v);
39358 if (match === false) {
39359 return true; // no more action?
39362 this.view.select(match);
39363 var sn = Roo.get(this.view.getSelectedNodes()[0])
39364 sn.scrollIntoView(sn.dom.parentNode, false);
39368 * @cfg {Boolean} grow
39372 * @cfg {Number} growMin
39376 * @cfg {Number} growMax
39384 * Copyright(c) 2010-2012, Roo J Solutions Limited
39391 * @class Roo.form.ComboBoxArray
39392 * @extends Roo.form.TextField
39393 * A facebook style adder... for lists of email / people / countries etc...
39394 * pick multiple items from a combo box, and shows each one.
39396 * Fred [x] Brian [x] [Pick another |v]
39399 * For this to work: it needs various extra information
39400 * - normal combo problay has
39402 * + displayField, valueField
39404 * For our purpose...
39407 * If we change from 'extends' to wrapping...
39414 * Create a new ComboBoxArray.
39415 * @param {Object} config Configuration options
39419 Roo.form.ComboBoxArray = function(config)
39422 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
39424 this.items = new Roo.util.MixedCollection(false);
39426 // construct the child combo...
39436 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
39439 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
39444 // behavies liek a hiddne field
39445 inputType: 'hidden',
39447 * @cfg {Number} width The width of the box that displays the selected element
39454 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
39458 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
39460 hiddenName : false,
39463 // private the array of items that are displayed..
39465 // private - the hidden field el.
39467 // private - the filed el..
39470 //validateValue : function() { return true; }, // all values are ok!
39471 //onAddClick: function() { },
39473 onRender : function(ct, position)
39476 // create the standard hidden element
39477 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
39480 // give fake names to child combo;
39481 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
39482 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
39484 this.combo = Roo.factory(this.combo, Roo.form);
39485 this.combo.onRender(ct, position);
39487 // assigned so form know we need to do this..
39488 this.store = this.combo.store;
39489 this.valueField = this.combo.valueField;
39490 this.displayField = this.combo.displayField ;
39493 this.combo.wrap.addClass('x-cbarray-grp');
39495 var cbwrap = this.combo.wrap.createChild(
39496 {tag: 'div', cls: 'x-cbarray-cb'},
39501 this.hiddenEl = this.combo.wrap.createChild({
39502 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
39504 this.el = this.combo.wrap.createChild({
39505 tag: 'input', type:'hidden' , name: this.name, value : ''
39507 // this.el.dom.removeAttribute("name");
39510 this.outerWrap = this.combo.wrap;
39511 this.wrap = cbwrap;
39513 this.outerWrap.setWidth(this.width);
39514 this.outerWrap.dom.removeChild(this.el.dom);
39516 this.wrap.dom.appendChild(this.el.dom);
39517 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
39518 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
39520 this.combo.trigger.setStyle('position','relative');
39521 this.combo.trigger.setStyle('left', '0px');
39522 this.combo.trigger.setStyle('top', '2px');
39524 this.combo.el.setStyle('vertical-align', 'text-bottom');
39526 //this.trigger.setStyle('vertical-align', 'top');
39528 // this should use the code from combo really... on('add' ....)
39532 this.adder = this.outerWrap.createChild(
39533 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
39535 this.adder.on('click', function(e) {
39536 _t.fireEvent('adderclick', this, e);
39540 //this.adder.on('click', this.onAddClick, _t);
39543 this.combo.on('select', function(cb, rec, ix) {
39544 this.addItem(rec.data);
39547 cb.el.dom.value = '';
39548 //cb.lastData = rec.data;
39557 getName: function()
39559 // returns hidden if it's set..
39560 if (!this.rendered) {return ''};
39561 return this.hiddenName ? this.hiddenName : this.name;
39566 onResize: function(w, h){
39569 // not sure if this is needed..
39570 //this.combo.onResize(w,h);
39572 if(typeof w != 'number'){
39573 // we do not handle it!?!?
39576 var tw = this.combo.trigger.getWidth();
39577 tw += this.addicon ? this.addicon.getWidth() : 0;
39578 tw += this.editicon ? this.editicon.getWidth() : 0;
39580 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
39582 this.combo.trigger.setStyle('left', '0px');
39584 if(this.list && this.listWidth === undefined){
39585 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
39586 this.list.setWidth(lw);
39587 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39594 addItem: function(rec)
39596 var valueField = this.combo.valueField;
39597 var displayField = this.combo.displayField;
39598 if (this.items.indexOfKey(rec[valueField]) > -1) {
39599 //console.log("GOT " + rec.data.id);
39603 var x = new Roo.form.ComboBoxArray.Item({
39604 //id : rec[this.idField],
39606 displayField : displayField ,
39607 tipField : displayField ,
39611 this.items.add(rec[valueField],x);
39612 // add it before the element..
39613 this.updateHiddenEl();
39614 x.render(this.outerWrap, this.wrap.dom);
39615 // add the image handler..
39618 updateHiddenEl : function()
39621 if (!this.hiddenEl) {
39625 var idField = this.combo.valueField;
39627 this.items.each(function(f) {
39628 ar.push(f.data[idField]);
39631 this.hiddenEl.dom.value = ar.join(',');
39637 //Roo.form.ComboBoxArray.superclass.reset.call(this);
39638 this.items.each(function(f) {
39641 this.el.dom.value = '';
39642 if (this.hiddenEl) {
39643 this.hiddenEl.dom.value = '';
39647 getValue: function()
39649 return this.hiddenEl ? this.hiddenEl.dom.value : '';
39651 setValue: function(v) // not a valid action - must use addItems..
39658 if (this.store.isLocal && (typeof(v) == 'string')) {
39659 // then we can use the store to find the values..
39660 // comma seperated at present.. this needs to allow JSON based encoding..
39661 this.hiddenEl.value = v;
39663 Roo.each(v.split(','), function(k) {
39664 Roo.log("CHECK " + this.valueField + ',' + k);
39665 var li = this.store.query(this.valueField, k);
39670 add[this.valueField] = k;
39671 add[this.displayField] = li.item(0).data[this.displayField];
39677 if (typeof(v) == 'object') {
39678 // then let's assume it's an array of objects..
39679 Roo.each(v, function(l) {
39687 setFromData: function(v)
39689 // this recieves an object, if setValues is called.
39691 this.el.dom.value = v[this.displayField];
39692 this.hiddenEl.dom.value = v[this.valueField];
39693 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
39696 var kv = v[this.valueField];
39697 var dv = v[this.displayField];
39698 kv = typeof(kv) != 'string' ? '' : kv;
39699 dv = typeof(dv) != 'string' ? '' : dv;
39702 var keys = kv.split(',');
39703 var display = dv.split(',');
39704 for (var i = 0 ; i < keys.length; i++) {
39707 add[this.valueField] = keys[i];
39708 add[this.displayField] = display[i];
39716 validateValue : function(value){
39717 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
39726 * @class Roo.form.ComboBoxArray.Item
39727 * @extends Roo.BoxComponent
39728 * A selected item in the list
39729 * Fred [x] Brian [x] [Pick another |v]
39732 * Create a new item.
39733 * @param {Object} config Configuration options
39736 Roo.form.ComboBoxArray.Item = function(config) {
39737 config.id = Roo.id();
39738 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
39741 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
39744 displayField : false,
39748 defaultAutoCreate : {
39750 cls: 'x-cbarray-item',
39757 src : Roo.BLANK_IMAGE_URL ,
39765 onRender : function(ct, position)
39767 Roo.form.Field.superclass.onRender.call(this, ct, position);
39770 var cfg = this.getAutoCreate();
39771 this.el = ct.createChild(cfg, position);
39774 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
39776 this.el.child('div').dom.innerHTML = this.cb.renderer ?
39777 this.cb.renderer(this.data) :
39778 String.format('{0}',this.data[this.displayField]);
39781 this.el.child('div').dom.setAttribute('qtip',
39782 String.format('{0}',this.data[this.tipField])
39785 this.el.child('img').on('click', this.remove, this);
39789 remove : function()
39792 this.cb.items.remove(this);
39793 this.el.child('img').un('click', this.remove, this);
39795 this.cb.updateHiddenEl();
39801 * Ext JS Library 1.1.1
39802 * Copyright(c) 2006-2007, Ext JS, LLC.
39804 * Originally Released Under LGPL - original licence link has changed is not relivant.
39807 * <script type="text/javascript">
39810 * @class Roo.form.Checkbox
39811 * @extends Roo.form.Field
39812 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
39814 * Creates a new Checkbox
39815 * @param {Object} config Configuration options
39817 Roo.form.Checkbox = function(config){
39818 Roo.form.Checkbox.superclass.constructor.call(this, config);
39822 * Fires when the checkbox is checked or unchecked.
39823 * @param {Roo.form.Checkbox} this This checkbox
39824 * @param {Boolean} checked The new checked value
39830 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
39832 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
39834 focusClass : undefined,
39836 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
39838 fieldClass: "x-form-field",
39840 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
39844 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39845 * {tag: "input", type: "checkbox", autocomplete: "off"})
39847 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
39849 * @cfg {String} boxLabel The text that appears beside the checkbox
39853 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
39857 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
39859 valueOff: '0', // value when not checked..
39861 actionMode : 'viewEl',
39864 itemCls : 'x-menu-check-item x-form-item',
39865 groupClass : 'x-menu-group-item',
39866 inputType : 'hidden',
39869 inSetChecked: false, // check that we are not calling self...
39871 inputElement: false, // real input element?
39872 basedOn: false, // ????
39874 isFormField: true, // not sure where this is needed!!!!
39876 onResize : function(){
39877 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
39878 if(!this.boxLabel){
39879 this.el.alignTo(this.wrap, 'c-c');
39883 initEvents : function(){
39884 Roo.form.Checkbox.superclass.initEvents.call(this);
39885 this.el.on("click", this.onClick, this);
39886 this.el.on("change", this.onClick, this);
39890 getResizeEl : function(){
39894 getPositionEl : function(){
39899 onRender : function(ct, position){
39900 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
39902 if(this.inputValue !== undefined){
39903 this.el.dom.value = this.inputValue;
39906 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
39907 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
39908 var viewEl = this.wrap.createChild({
39909 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
39910 this.viewEl = viewEl;
39911 this.wrap.on('click', this.onClick, this);
39913 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
39914 this.el.on('propertychange', this.setFromHidden, this); //ie
39919 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
39920 // viewEl.on('click', this.onClick, this);
39922 //if(this.checked){
39923 this.setChecked(this.checked);
39925 //this.checked = this.el.dom;
39931 initValue : Roo.emptyFn,
39934 * Returns the checked state of the checkbox.
39935 * @return {Boolean} True if checked, else false
39937 getValue : function(){
39939 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
39941 return this.valueOff;
39946 onClick : function(){
39947 this.setChecked(!this.checked);
39949 //if(this.el.dom.checked != this.checked){
39950 // this.setValue(this.el.dom.checked);
39955 * Sets the checked state of the checkbox.
39956 * On is always based on a string comparison between inputValue and the param.
39957 * @param {Boolean/String} value - the value to set
39958 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
39960 setValue : function(v,suppressEvent){
39963 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
39964 //if(this.el && this.el.dom){
39965 // this.el.dom.checked = this.checked;
39966 // this.el.dom.defaultChecked = this.checked;
39968 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
39969 //this.fireEvent("check", this, this.checked);
39972 setChecked : function(state,suppressEvent)
39974 if (this.inSetChecked) {
39975 this.checked = state;
39981 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
39983 this.checked = state;
39984 if(suppressEvent !== true){
39985 this.fireEvent('check', this, state);
39987 this.inSetChecked = true;
39988 this.el.dom.value = state ? this.inputValue : this.valueOff;
39989 this.inSetChecked = false;
39992 // handle setting of hidden value by some other method!!?!?
39993 setFromHidden: function()
39998 //console.log("SET FROM HIDDEN");
39999 //alert('setFrom hidden');
40000 this.setValue(this.el.dom.value);
40003 onDestroy : function()
40006 Roo.get(this.viewEl).remove();
40009 Roo.form.Checkbox.superclass.onDestroy.call(this);
40014 * Ext JS Library 1.1.1
40015 * Copyright(c) 2006-2007, Ext JS, LLC.
40017 * Originally Released Under LGPL - original licence link has changed is not relivant.
40020 * <script type="text/javascript">
40024 * @class Roo.form.Radio
40025 * @extends Roo.form.Checkbox
40026 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40027 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40029 * Creates a new Radio
40030 * @param {Object} config Configuration options
40032 Roo.form.Radio = function(){
40033 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40035 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40036 inputType: 'radio',
40039 * If this radio is part of a group, it will return the selected value
40042 getGroupValue : function(){
40043 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40045 });//<script type="text/javascript">
40048 * Ext JS Library 1.1.1
40049 * Copyright(c) 2006-2007, Ext JS, LLC.
40050 * licensing@extjs.com
40052 * http://www.extjs.com/license
40058 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40059 * - IE ? - no idea how much works there.
40067 * @class Ext.form.HtmlEditor
40068 * @extends Ext.form.Field
40069 * Provides a lightweight HTML Editor component.
40071 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40073 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40074 * supported by this editor.</b><br/><br/>
40075 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40076 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40078 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40080 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40084 * @cfg {String} createLinkText The default text for the create link prompt
40086 createLinkText : 'Please enter the URL for the link:',
40088 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40090 defaultLinkValue : 'http:/'+'/',
40093 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40098 * @cfg {Number} height (in pixels)
40102 * @cfg {Number} width (in pixels)
40107 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40110 stylesheets: false,
40115 // private properties
40116 validationEvent : false,
40118 initialized : false,
40120 sourceEditMode : false,
40121 onFocus : Roo.emptyFn,
40123 hideMode:'offsets',
40125 defaultAutoCreate : { // modified by initCompnoent..
40127 style:"width:500px;height:300px;",
40128 autocomplete: "off"
40132 initComponent : function(){
40135 * @event initialize
40136 * Fires when the editor is fully initialized (including the iframe)
40137 * @param {HtmlEditor} this
40142 * Fires when the editor is first receives the focus. Any insertion must wait
40143 * until after this event.
40144 * @param {HtmlEditor} this
40148 * @event beforesync
40149 * Fires before the textarea is updated with content from the editor iframe. Return false
40150 * to cancel the sync.
40151 * @param {HtmlEditor} this
40152 * @param {String} html
40156 * @event beforepush
40157 * Fires before the iframe editor is updated with content from the textarea. Return false
40158 * to cancel the push.
40159 * @param {HtmlEditor} this
40160 * @param {String} html
40165 * Fires when the textarea is updated with content from the editor iframe.
40166 * @param {HtmlEditor} this
40167 * @param {String} html
40172 * Fires when the iframe editor is updated with content from the textarea.
40173 * @param {HtmlEditor} this
40174 * @param {String} html
40178 * @event editmodechange
40179 * Fires when the editor switches edit modes
40180 * @param {HtmlEditor} this
40181 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40183 editmodechange: true,
40185 * @event editorevent
40186 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40187 * @param {HtmlEditor} this
40191 this.defaultAutoCreate = {
40193 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40194 autocomplete: "off"
40199 * Protected method that will not generally be called directly. It
40200 * is called when the editor creates its toolbar. Override this method if you need to
40201 * add custom toolbar buttons.
40202 * @param {HtmlEditor} editor
40204 createToolbar : function(editor){
40205 if (!editor.toolbars || !editor.toolbars.length) {
40206 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40209 for (var i =0 ; i < editor.toolbars.length;i++) {
40210 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
40211 editor.toolbars[i].init(editor);
40218 * Protected method that will not generally be called directly. It
40219 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40220 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40222 getDocMarkup : function(){
40225 if (this.stylesheets === false) {
40227 Roo.get(document.head).select('style').each(function(node) {
40228 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40231 Roo.get(document.head).select('link').each(function(node) {
40232 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40235 } else if (!this.stylesheets.length) {
40237 st = '<style type="text/css">' +
40238 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40241 Roo.each(this.stylesheets, function(s) {
40242 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
40247 st += '<style type="text/css">' +
40248 'IMG { cursor: pointer } ' +
40252 return '<html><head>' + st +
40253 //<style type="text/css">' +
40254 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40256 ' </head><body class="roo-htmleditor-body"></body></html>';
40260 onRender : function(ct, position)
40263 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
40264 this.el.dom.style.border = '0 none';
40265 this.el.dom.setAttribute('tabIndex', -1);
40266 this.el.addClass('x-hidden');
40267 if(Roo.isIE){ // fix IE 1px bogus margin
40268 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
40270 this.wrap = this.el.wrap({
40271 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
40274 if (this.resizable) {
40275 this.resizeEl = new Roo.Resizable(this.wrap, {
40279 minHeight : this.height,
40280 height: this.height,
40281 handles : this.resizable,
40284 resize : function(r, w, h) {
40285 _t.onResize(w,h); // -something
40292 this.frameId = Roo.id();
40294 this.createToolbar(this);
40298 var iframe = this.wrap.createChild({
40301 name: this.frameId,
40302 frameBorder : 'no',
40303 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
40307 // console.log(iframe);
40308 //this.wrap.dom.appendChild(iframe);
40310 this.iframe = iframe.dom;
40312 this.assignDocWin();
40314 this.doc.designMode = 'on';
40317 this.doc.write(this.getDocMarkup());
40321 var task = { // must defer to wait for browser to be ready
40323 //console.log("run task?" + this.doc.readyState);
40324 this.assignDocWin();
40325 if(this.doc.body || this.doc.readyState == 'complete'){
40327 this.doc.designMode="on";
40331 Roo.TaskMgr.stop(task);
40332 this.initEditor.defer(10, this);
40339 Roo.TaskMgr.start(task);
40342 this.setSize(this.wrap.getSize());
40344 if (this.resizeEl) {
40345 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
40346 // should trigger onReize..
40351 onResize : function(w, h)
40353 //Roo.log('resize: ' +w + ',' + h );
40354 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
40355 if(this.el && this.iframe){
40356 if(typeof w == 'number'){
40357 var aw = w - this.wrap.getFrameWidth('lr');
40358 this.el.setWidth(this.adjustWidth('textarea', aw));
40359 this.iframe.style.width = aw + 'px';
40361 if(typeof h == 'number'){
40363 for (var i =0; i < this.toolbars.length;i++) {
40364 // fixme - ask toolbars for heights?
40365 tbh += this.toolbars[i].tb.el.getHeight();
40366 if (this.toolbars[i].footer) {
40367 tbh += this.toolbars[i].footer.el.getHeight();
40374 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
40375 ah -= 5; // knock a few pixes off for look..
40376 this.el.setHeight(this.adjustWidth('textarea', ah));
40377 this.iframe.style.height = ah + 'px';
40379 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
40386 * Toggles the editor between standard and source edit mode.
40387 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
40389 toggleSourceEdit : function(sourceEditMode){
40391 this.sourceEditMode = sourceEditMode === true;
40393 if(this.sourceEditMode){
40396 this.iframe.className = 'x-hidden';
40397 this.el.removeClass('x-hidden');
40398 this.el.dom.removeAttribute('tabIndex');
40403 this.iframe.className = '';
40404 this.el.addClass('x-hidden');
40405 this.el.dom.setAttribute('tabIndex', -1);
40408 this.setSize(this.wrap.getSize());
40409 this.fireEvent('editmodechange', this, this.sourceEditMode);
40412 // private used internally
40413 createLink : function(){
40414 var url = prompt(this.createLinkText, this.defaultLinkValue);
40415 if(url && url != 'http:/'+'/'){
40416 this.relayCmd('createlink', url);
40420 // private (for BoxComponent)
40421 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40423 // private (for BoxComponent)
40424 getResizeEl : function(){
40428 // private (for BoxComponent)
40429 getPositionEl : function(){
40434 initEvents : function(){
40435 this.originalValue = this.getValue();
40439 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40442 markInvalid : Roo.emptyFn,
40444 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40447 clearInvalid : Roo.emptyFn,
40449 setValue : function(v){
40450 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
40455 * Protected method that will not generally be called directly. If you need/want
40456 * custom HTML cleanup, this is the method you should override.
40457 * @param {String} html The HTML to be cleaned
40458 * return {String} The cleaned HTML
40460 cleanHtml : function(html){
40461 html = String(html);
40462 if(html.length > 5){
40463 if(Roo.isSafari){ // strip safari nonsense
40464 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
40467 if(html == ' '){
40474 * Protected method that will not generally be called directly. Syncs the contents
40475 * of the editor iframe with the textarea.
40477 syncValue : function(){
40478 if(this.initialized){
40479 var bd = (this.doc.body || this.doc.documentElement);
40480 //this.cleanUpPaste(); -- this is done else where and causes havoc..
40481 var html = bd.innerHTML;
40483 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
40484 var m = bs.match(/text-align:(.*?);/i);
40486 html = '<div style="'+m[0]+'">' + html + '</div>';
40489 html = this.cleanHtml(html);
40490 // fix up the special chars..
40491 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
40492 return "&#"+b.charCodeAt()+";"
40494 if(this.fireEvent('beforesync', this, html) !== false){
40495 this.el.dom.value = html;
40496 this.fireEvent('sync', this, html);
40502 * Protected method that will not generally be called directly. Pushes the value of the textarea
40503 * into the iframe editor.
40505 pushValue : function(){
40506 if(this.initialized){
40507 var v = this.el.dom.value;
40512 if(this.fireEvent('beforepush', this, v) !== false){
40513 var d = (this.doc.body || this.doc.documentElement);
40515 this.cleanUpPaste();
40516 this.el.dom.value = d.innerHTML;
40517 this.fireEvent('push', this, v);
40523 deferFocus : function(){
40524 this.focus.defer(10, this);
40528 focus : function(){
40529 if(this.win && !this.sourceEditMode){
40536 assignDocWin: function()
40538 var iframe = this.iframe;
40541 this.doc = iframe.contentWindow.document;
40542 this.win = iframe.contentWindow;
40544 if (!Roo.get(this.frameId)) {
40547 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
40548 this.win = Roo.get(this.frameId).dom.contentWindow;
40553 initEditor : function(){
40554 //console.log("INIT EDITOR");
40555 this.assignDocWin();
40559 this.doc.designMode="on";
40561 this.doc.write(this.getDocMarkup());
40564 var dbody = (this.doc.body || this.doc.documentElement);
40565 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
40566 // this copies styles from the containing element into thsi one..
40567 // not sure why we need all of this..
40568 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
40569 ss['background-attachment'] = 'fixed'; // w3c
40570 dbody.bgProperties = 'fixed'; // ie
40571 Roo.DomHelper.applyStyles(dbody, ss);
40572 Roo.EventManager.on(this.doc, {
40573 //'mousedown': this.onEditorEvent,
40574 'mouseup': this.onEditorEvent,
40575 'dblclick': this.onEditorEvent,
40576 'click': this.onEditorEvent,
40577 'keyup': this.onEditorEvent,
40582 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
40584 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
40585 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
40587 this.initialized = true;
40589 this.fireEvent('initialize', this);
40594 onDestroy : function(){
40600 for (var i =0; i < this.toolbars.length;i++) {
40601 // fixme - ask toolbars for heights?
40602 this.toolbars[i].onDestroy();
40605 this.wrap.dom.innerHTML = '';
40606 this.wrap.remove();
40611 onFirstFocus : function(){
40613 this.assignDocWin();
40616 this.activated = true;
40617 for (var i =0; i < this.toolbars.length;i++) {
40618 this.toolbars[i].onFirstFocus();
40621 if(Roo.isGecko){ // prevent silly gecko errors
40623 var s = this.win.getSelection();
40624 if(!s.focusNode || s.focusNode.nodeType != 3){
40625 var r = s.getRangeAt(0);
40626 r.selectNodeContents((this.doc.body || this.doc.documentElement));
40631 this.execCmd('useCSS', true);
40632 this.execCmd('styleWithCSS', false);
40635 this.fireEvent('activate', this);
40639 adjustFont: function(btn){
40640 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
40641 //if(Roo.isSafari){ // safari
40644 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
40645 if(Roo.isSafari){ // safari
40646 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
40647 v = (v < 10) ? 10 : v;
40648 v = (v > 48) ? 48 : v;
40649 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
40654 v = Math.max(1, v+adjust);
40656 this.execCmd('FontSize', v );
40659 onEditorEvent : function(e){
40660 this.fireEvent('editorevent', this, e);
40661 // this.updateToolbar();
40662 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
40665 insertTag : function(tg)
40667 // could be a bit smarter... -> wrap the current selected tRoo..
40669 this.execCmd("formatblock", tg);
40673 insertText : function(txt)
40677 range = this.createRange();
40678 range.deleteContents();
40679 //alert(Sender.getAttribute('label'));
40681 range.insertNode(this.doc.createTextNode(txt));
40685 relayBtnCmd : function(btn){
40686 this.relayCmd(btn.cmd);
40690 * Executes a Midas editor command on the editor document and performs necessary focus and
40691 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
40692 * @param {String} cmd The Midas command
40693 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40695 relayCmd : function(cmd, value){
40697 this.execCmd(cmd, value);
40698 this.fireEvent('editorevent', this);
40699 //this.updateToolbar();
40704 * Executes a Midas editor command directly on the editor document.
40705 * For visual commands, you should use {@link #relayCmd} instead.
40706 * <b>This should only be called after the editor is initialized.</b>
40707 * @param {String} cmd The Midas command
40708 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40710 execCmd : function(cmd, value){
40711 this.doc.execCommand(cmd, false, value === undefined ? null : value);
40718 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
40720 * @param {String} text | dom node..
40722 insertAtCursor : function(text)
40727 if(!this.activated){
40733 var r = this.doc.selection.createRange();
40744 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
40748 // from jquery ui (MIT licenced)
40750 var win = this.win;
40752 if (win.getSelection && win.getSelection().getRangeAt) {
40753 range = win.getSelection().getRangeAt(0);
40754 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
40755 range.insertNode(node);
40756 } else if (win.document.selection && win.document.selection.createRange) {
40757 // no firefox support
40758 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40759 win.document.selection.createRange().pasteHTML(txt);
40761 // no firefox support
40762 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40763 this.execCmd('InsertHTML', txt);
40772 mozKeyPress : function(e){
40774 var c = e.getCharCode(), cmd;
40777 c = String.fromCharCode(c).toLowerCase();
40791 this.cleanUpPaste.defer(100, this);
40799 e.preventDefault();
40807 fixKeys : function(){ // load time branching for fastest keydown performance
40809 return function(e){
40810 var k = e.getKey(), r;
40813 r = this.doc.selection.createRange();
40816 r.pasteHTML('    ');
40823 r = this.doc.selection.createRange();
40825 var target = r.parentElement();
40826 if(!target || target.tagName.toLowerCase() != 'li'){
40828 r.pasteHTML('<br />');
40834 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40835 this.cleanUpPaste.defer(100, this);
40841 }else if(Roo.isOpera){
40842 return function(e){
40843 var k = e.getKey();
40847 this.execCmd('InsertHTML','    ');
40850 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40851 this.cleanUpPaste.defer(100, this);
40856 }else if(Roo.isSafari){
40857 return function(e){
40858 var k = e.getKey();
40862 this.execCmd('InsertText','\t');
40866 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40867 this.cleanUpPaste.defer(100, this);
40875 getAllAncestors: function()
40877 var p = this.getSelectedNode();
40880 a.push(p); // push blank onto stack..
40881 p = this.getParentElement();
40885 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
40889 a.push(this.doc.body);
40893 lastSelNode : false,
40896 getSelection : function()
40898 this.assignDocWin();
40899 return Roo.isIE ? this.doc.selection : this.win.getSelection();
40902 getSelectedNode: function()
40904 // this may only work on Gecko!!!
40906 // should we cache this!!!!
40911 var range = this.createRange(this.getSelection()).cloneRange();
40914 var parent = range.parentElement();
40916 var testRange = range.duplicate();
40917 testRange.moveToElementText(parent);
40918 if (testRange.inRange(range)) {
40921 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
40924 parent = parent.parentElement;
40929 // is ancestor a text element.
40930 var ac = range.commonAncestorContainer;
40931 if (ac.nodeType == 3) {
40932 ac = ac.parentNode;
40935 var ar = ac.childNodes;
40938 var other_nodes = [];
40939 var has_other_nodes = false;
40940 for (var i=0;i<ar.length;i++) {
40941 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
40944 // fullly contained node.
40946 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
40951 // probably selected..
40952 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
40953 other_nodes.push(ar[i]);
40957 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
40962 has_other_nodes = true;
40964 if (!nodes.length && other_nodes.length) {
40965 nodes= other_nodes;
40967 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
40973 createRange: function(sel)
40975 // this has strange effects when using with
40976 // top toolbar - not sure if it's a great idea.
40977 //this.editor.contentWindow.focus();
40978 if (typeof sel != "undefined") {
40980 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
40982 return this.doc.createRange();
40985 return this.doc.createRange();
40988 getParentElement: function()
40991 this.assignDocWin();
40992 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
40994 var range = this.createRange(sel);
40997 var p = range.commonAncestorContainer;
40998 while (p.nodeType == 3) { // text node
41009 * Range intersection.. the hard stuff...
41013 * [ -- selected range --- ]
41017 * if end is before start or hits it. fail.
41018 * if start is after end or hits it fail.
41020 * if either hits (but other is outside. - then it's not
41026 // @see http://www.thismuchiknow.co.uk/?p=64.
41027 rangeIntersectsNode : function(range, node)
41029 var nodeRange = node.ownerDocument.createRange();
41031 nodeRange.selectNode(node);
41033 nodeRange.selectNodeContents(node);
41036 var rangeStartRange = range.cloneRange();
41037 rangeStartRange.collapse(true);
41039 var rangeEndRange = range.cloneRange();
41040 rangeEndRange.collapse(false);
41042 var nodeStartRange = nodeRange.cloneRange();
41043 nodeStartRange.collapse(true);
41045 var nodeEndRange = nodeRange.cloneRange();
41046 nodeEndRange.collapse(false);
41048 return rangeStartRange.compareBoundaryPoints(
41049 Range.START_TO_START, nodeEndRange) == -1 &&
41050 rangeEndRange.compareBoundaryPoints(
41051 Range.START_TO_START, nodeStartRange) == 1;
41055 rangeCompareNode : function(range, node)
41057 var nodeRange = node.ownerDocument.createRange();
41059 nodeRange.selectNode(node);
41061 nodeRange.selectNodeContents(node);
41065 range.collapse(true);
41067 nodeRange.collapse(true);
41069 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41070 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41072 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41074 var nodeIsBefore = ss == 1;
41075 var nodeIsAfter = ee == -1;
41077 if (nodeIsBefore && nodeIsAfter)
41079 if (!nodeIsBefore && nodeIsAfter)
41080 return 1; //right trailed.
41082 if (nodeIsBefore && !nodeIsAfter)
41083 return 2; // left trailed.
41088 // private? - in a new class?
41089 cleanUpPaste : function()
41091 // cleans up the whole document..
41092 Roo.log('cleanuppaste');
41093 this.cleanUpChildren(this.doc.body);
41094 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41095 if (clean != this.doc.body.innerHTML) {
41096 this.doc.body.innerHTML = clean;
41101 cleanWordChars : function(input) {
41102 var he = Roo.form.HtmlEditor;
41104 var output = input;
41105 Roo.each(he.swapCodes, function(sw) {
41107 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41108 output = output.replace(swapper, sw[1]);
41114 cleanUpChildren : function (n)
41116 if (!n.childNodes.length) {
41119 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41120 this.cleanUpChild(n.childNodes[i]);
41127 cleanUpChild : function (node)
41129 //console.log(node);
41130 if (node.nodeName == "#text") {
41131 // clean up silly Windows -- stuff?
41134 if (node.nodeName == "#comment") {
41135 node.parentNode.removeChild(node);
41136 // clean up silly Windows -- stuff?
41140 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41142 node.parentNode.removeChild(node);
41147 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41149 // remove <a name=....> as rendering on yahoo mailer is bored with this.
41151 if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41152 remove_keep_children = true;
41155 if (remove_keep_children) {
41156 this.cleanUpChildren(node);
41157 // inserts everything just before this node...
41158 while (node.childNodes.length) {
41159 var cn = node.childNodes[0];
41160 node.removeChild(cn);
41161 node.parentNode.insertBefore(cn, node);
41163 node.parentNode.removeChild(node);
41167 if (!node.attributes || !node.attributes.length) {
41168 this.cleanUpChildren(node);
41172 function cleanAttr(n,v)
41175 if (v.match(/^\./) || v.match(/^\//)) {
41178 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41181 if (v.match(/^#/)) {
41184 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
41185 node.removeAttribute(n);
41189 function cleanStyle(n,v)
41191 if (v.match(/expression/)) { //XSS?? should we even bother..
41192 node.removeAttribute(n);
41197 var parts = v.split(/;/);
41198 Roo.each(parts, function(p) {
41199 p = p.replace(/\s+/g,'');
41203 var l = p.split(':').shift().replace(/\s+/g,'');
41205 // only allow 'c whitelisted system attributes'
41206 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
41207 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
41208 node.removeAttribute(n);
41218 for (var i = node.attributes.length-1; i > -1 ; i--) {
41219 var a = node.attributes[i];
41221 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
41222 node.removeAttribute(a.name);
41225 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
41226 cleanAttr(a.name,a.value); // fixme..
41229 if (a.name == 'style') {
41230 cleanStyle(a.name,a.value);
41233 /// clean up MS crap..
41234 // tecnically this should be a list of valid class'es..
41237 if (a.name == 'class') {
41238 if (a.value.match(/^Mso/)) {
41239 node.className = '';
41242 if (a.value.match(/body/)) {
41243 node.className = '';
41254 this.cleanUpChildren(node);
41260 // hide stuff that is not compatible
41274 * @event specialkey
41278 * @cfg {String} fieldClass @hide
41281 * @cfg {String} focusClass @hide
41284 * @cfg {String} autoCreate @hide
41287 * @cfg {String} inputType @hide
41290 * @cfg {String} invalidClass @hide
41293 * @cfg {String} invalidText @hide
41296 * @cfg {String} msgFx @hide
41299 * @cfg {String} validateOnBlur @hide
41303 Roo.form.HtmlEditor.white = [
41304 'area', 'br', 'img', 'input', 'hr', 'wbr',
41306 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
41307 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
41308 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
41309 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
41310 'table', 'ul', 'xmp',
41312 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
41315 'dir', 'menu', 'ol', 'ul', 'dl',
41321 Roo.form.HtmlEditor.black = [
41322 // 'embed', 'object', // enable - backend responsiblity to clean thiese
41324 'base', 'basefont', 'bgsound', 'blink', 'body',
41325 'frame', 'frameset', 'head', 'html', 'ilayer',
41326 'iframe', 'layer', 'link', 'meta', 'object',
41327 'script', 'style' ,'title', 'xml' // clean later..
41329 Roo.form.HtmlEditor.clean = [
41330 'script', 'style', 'title', 'xml'
41332 Roo.form.HtmlEditor.remove = [
41337 Roo.form.HtmlEditor.ablack = [
41341 Roo.form.HtmlEditor.aclean = [
41342 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
41346 Roo.form.HtmlEditor.pwhite= [
41347 'http', 'https', 'mailto'
41350 // white listed style attributes.
41351 Roo.form.HtmlEditor.cwhite= [
41357 Roo.form.HtmlEditor.swapCodes =[
41368 // <script type="text/javascript">
41371 * Ext JS Library 1.1.1
41372 * Copyright(c) 2006-2007, Ext JS, LLC.
41378 * @class Roo.form.HtmlEditorToolbar1
41383 new Roo.form.HtmlEditor({
41386 new Roo.form.HtmlEditorToolbar1({
41387 disable : { fonts: 1 , format: 1, ..., ... , ...],
41393 * @cfg {Object} disable List of elements to disable..
41394 * @cfg {Array} btns List of additional buttons.
41398 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
41401 Roo.form.HtmlEditor.ToolbarStandard = function(config)
41404 Roo.apply(this, config);
41406 // default disabled, based on 'good practice'..
41407 this.disable = this.disable || {};
41408 Roo.applyIf(this.disable, {
41411 specialElements : true
41415 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41416 // dont call parent... till later.
41419 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
41427 * @cfg {Object} disable List of toolbar elements to disable
41432 * @cfg {Array} fontFamilies An array of available font families
41450 // "á" , ?? a acute?
41455 "°" // , // degrees
41457 // "é" , // e ecute
41458 // "ú" , // u ecute?
41461 specialElements : [
41463 text: "Insert Table",
41466 ihtml : '<table><tr><td>Cell</td></tr></table>'
41470 text: "Insert Image",
41473 ihtml : '<img src="about:blank"/>'
41482 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
41483 "input:submit", "input:button", "select", "textarea", "label" ],
41486 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
41488 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
41491 * @cfg {String} defaultFont default font to use.
41493 defaultFont: 'tahoma',
41495 fontSelect : false,
41498 formatCombo : false,
41500 init : function(editor)
41502 this.editor = editor;
41505 var fid = editor.frameId;
41507 function btn(id, toggle, handler){
41508 var xid = fid + '-'+ id ;
41512 cls : 'x-btn-icon x-edit-'+id,
41513 enableToggle:toggle !== false,
41514 scope: editor, // was editor...
41515 handler:handler||editor.relayBtnCmd,
41516 clickEvent:'mousedown',
41517 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41524 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41526 // stop form submits
41527 tb.el.on('click', function(e){
41528 e.preventDefault(); // what does this do?
41531 if(!this.disable.font && !Roo.isSafari){
41532 /* why no safari for fonts
41533 editor.fontSelect = tb.el.createChild({
41536 cls:'x-font-select',
41537 html: editor.createFontOptions()
41539 editor.fontSelect.on('change', function(){
41540 var font = editor.fontSelect.dom.value;
41541 editor.relayCmd('fontname', font);
41542 editor.deferFocus();
41545 editor.fontSelect.dom,
41550 if(!this.disable.formats){
41551 this.formatCombo = new Roo.form.ComboBox({
41552 store: new Roo.data.SimpleStore({
41555 data : this.formats // from states.js
41558 //autoCreate : {tag: "div", size: "20"},
41559 displayField:'tag',
41563 triggerAction: 'all',
41564 emptyText:'Add tag',
41565 selectOnFocus:true,
41568 'select': function(c, r, i) {
41569 editor.insertTag(r.get('tag'));
41575 tb.addField(this.formatCombo);
41579 if(!this.disable.format){
41586 if(!this.disable.fontSize){
41591 btn('increasefontsize', false, editor.adjustFont),
41592 btn('decreasefontsize', false, editor.adjustFont)
41597 if(!this.disable.colors){
41600 id:editor.frameId +'-forecolor',
41601 cls:'x-btn-icon x-edit-forecolor',
41602 clickEvent:'mousedown',
41603 tooltip: this.buttonTips['forecolor'] || undefined,
41605 menu : new Roo.menu.ColorMenu({
41606 allowReselect: true,
41607 focus: Roo.emptyFn,
41610 selectHandler: function(cp, color){
41611 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41612 editor.deferFocus();
41615 clickEvent:'mousedown'
41618 id:editor.frameId +'backcolor',
41619 cls:'x-btn-icon x-edit-backcolor',
41620 clickEvent:'mousedown',
41621 tooltip: this.buttonTips['backcolor'] || undefined,
41623 menu : new Roo.menu.ColorMenu({
41624 focus: Roo.emptyFn,
41627 allowReselect: true,
41628 selectHandler: function(cp, color){
41630 editor.execCmd('useCSS', false);
41631 editor.execCmd('hilitecolor', color);
41632 editor.execCmd('useCSS', true);
41633 editor.deferFocus();
41635 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41636 Roo.isSafari || Roo.isIE ? '#'+color : color);
41637 editor.deferFocus();
41641 clickEvent:'mousedown'
41646 // now add all the items...
41649 if(!this.disable.alignments){
41652 btn('justifyleft'),
41653 btn('justifycenter'),
41654 btn('justifyright')
41658 //if(!Roo.isSafari){
41659 if(!this.disable.links){
41662 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41666 if(!this.disable.lists){
41669 btn('insertorderedlist'),
41670 btn('insertunorderedlist')
41673 if(!this.disable.sourceEdit){
41676 btn('sourceedit', true, function(btn){
41677 this.toggleSourceEdit(btn.pressed);
41684 // special menu.. - needs to be tidied up..
41685 if (!this.disable.special) {
41688 cls: 'x-edit-none',
41694 for (var i =0; i < this.specialChars.length; i++) {
41695 smenu.menu.items.push({
41697 html: this.specialChars[i],
41698 handler: function(a,b) {
41699 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41700 //editor.insertAtCursor(a.html);
41713 if (!this.disable.specialElements) {
41716 cls: 'x-edit-none',
41721 for (var i =0; i < this.specialElements.length; i++) {
41722 semenu.menu.items.push(
41724 handler: function(a,b) {
41725 editor.insertAtCursor(this.ihtml);
41727 }, this.specialElements[i])
41739 for(var i =0; i< this.btns.length;i++) {
41740 var b = Roo.factory(this.btns[i],Roo.form);
41741 b.cls = 'x-edit-none';
41750 // disable everything...
41752 this.tb.items.each(function(item){
41753 if(item.id != editor.frameId+ '-sourceedit'){
41757 this.rendered = true;
41759 // the all the btns;
41760 editor.on('editorevent', this.updateToolbar, this);
41761 // other toolbars need to implement this..
41762 //editor.on('editmodechange', this.updateToolbar, this);
41768 * Protected method that will not generally be called directly. It triggers
41769 * a toolbar update by reading the markup state of the current selection in the editor.
41771 updateToolbar: function(){
41773 if(!this.editor.activated){
41774 this.editor.onFirstFocus();
41778 var btns = this.tb.items.map,
41779 doc = this.editor.doc,
41780 frameId = this.editor.frameId;
41782 if(!this.disable.font && !Roo.isSafari){
41784 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
41785 if(name != this.fontSelect.dom.value){
41786 this.fontSelect.dom.value = name;
41790 if(!this.disable.format){
41791 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
41792 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
41793 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
41795 if(!this.disable.alignments){
41796 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
41797 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
41798 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
41800 if(!Roo.isSafari && !this.disable.lists){
41801 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
41802 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
41805 var ans = this.editor.getAllAncestors();
41806 if (this.formatCombo) {
41809 var store = this.formatCombo.store;
41810 this.formatCombo.setValue("");
41811 for (var i =0; i < ans.length;i++) {
41812 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
41814 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
41822 // hides menus... - so this cant be on a menu...
41823 Roo.menu.MenuMgr.hideAll();
41825 //this.editorsyncValue();
41829 createFontOptions : function(){
41830 var buf = [], fs = this.fontFamilies, ff, lc;
41831 for(var i = 0, len = fs.length; i< len; i++){
41833 lc = ff.toLowerCase();
41835 '<option value="',lc,'" style="font-family:',ff,';"',
41836 (this.defaultFont == lc ? ' selected="true">' : '>'),
41841 return buf.join('');
41844 toggleSourceEdit : function(sourceEditMode){
41845 if(sourceEditMode === undefined){
41846 sourceEditMode = !this.sourceEditMode;
41848 this.sourceEditMode = sourceEditMode === true;
41849 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
41850 // just toggle the button?
41851 if(btn.pressed !== this.editor.sourceEditMode){
41852 btn.toggle(this.editor.sourceEditMode);
41856 if(this.sourceEditMode){
41857 this.tb.items.each(function(item){
41858 if(item.cmd != 'sourceedit'){
41864 if(this.initialized){
41865 this.tb.items.each(function(item){
41871 // tell the editor that it's been pressed..
41872 this.editor.toggleSourceEdit(sourceEditMode);
41876 * Object collection of toolbar tooltips for the buttons in the editor. The key
41877 * is the command id associated with that button and the value is a valid QuickTips object.
41882 title: 'Bold (Ctrl+B)',
41883 text: 'Make the selected text bold.',
41884 cls: 'x-html-editor-tip'
41887 title: 'Italic (Ctrl+I)',
41888 text: 'Make the selected text italic.',
41889 cls: 'x-html-editor-tip'
41897 title: 'Bold (Ctrl+B)',
41898 text: 'Make the selected text bold.',
41899 cls: 'x-html-editor-tip'
41902 title: 'Italic (Ctrl+I)',
41903 text: 'Make the selected text italic.',
41904 cls: 'x-html-editor-tip'
41907 title: 'Underline (Ctrl+U)',
41908 text: 'Underline the selected text.',
41909 cls: 'x-html-editor-tip'
41911 increasefontsize : {
41912 title: 'Grow Text',
41913 text: 'Increase the font size.',
41914 cls: 'x-html-editor-tip'
41916 decreasefontsize : {
41917 title: 'Shrink Text',
41918 text: 'Decrease the font size.',
41919 cls: 'x-html-editor-tip'
41922 title: 'Text Highlight Color',
41923 text: 'Change the background color of the selected text.',
41924 cls: 'x-html-editor-tip'
41927 title: 'Font Color',
41928 text: 'Change the color of the selected text.',
41929 cls: 'x-html-editor-tip'
41932 title: 'Align Text Left',
41933 text: 'Align text to the left.',
41934 cls: 'x-html-editor-tip'
41937 title: 'Center Text',
41938 text: 'Center text in the editor.',
41939 cls: 'x-html-editor-tip'
41942 title: 'Align Text Right',
41943 text: 'Align text to the right.',
41944 cls: 'x-html-editor-tip'
41946 insertunorderedlist : {
41947 title: 'Bullet List',
41948 text: 'Start a bulleted list.',
41949 cls: 'x-html-editor-tip'
41951 insertorderedlist : {
41952 title: 'Numbered List',
41953 text: 'Start a numbered list.',
41954 cls: 'x-html-editor-tip'
41957 title: 'Hyperlink',
41958 text: 'Make the selected text a hyperlink.',
41959 cls: 'x-html-editor-tip'
41962 title: 'Source Edit',
41963 text: 'Switch to source editing mode.',
41964 cls: 'x-html-editor-tip'
41968 onDestroy : function(){
41971 this.tb.items.each(function(item){
41973 item.menu.removeAll();
41975 item.menu.el.destroy();
41983 onFirstFocus: function() {
41984 this.tb.items.each(function(item){
41993 // <script type="text/javascript">
41996 * Ext JS Library 1.1.1
41997 * Copyright(c) 2006-2007, Ext JS, LLC.
42004 * @class Roo.form.HtmlEditor.ToolbarContext
42009 new Roo.form.HtmlEditor({
42012 { xtype: 'ToolbarStandard', styles : {} }
42013 { xtype: 'ToolbarContext', disable : {} }
42019 * @config : {Object} disable List of elements to disable.. (not done yet.)
42020 * @config : {Object} styles Map of styles available.
42024 Roo.form.HtmlEditor.ToolbarContext = function(config)
42027 Roo.apply(this, config);
42028 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42029 // dont call parent... till later.
42030 this.styles = this.styles || {};
42032 Roo.form.HtmlEditor.ToolbarContext.types = {
42044 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42106 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42111 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42165 // should we really allow this??
42166 // should this just be
42181 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
42189 * @cfg {Object} disable List of toolbar elements to disable
42194 * @cfg {Object} styles List of styles
42195 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
42197 * These must be defined in the page, so they get rendered correctly..
42208 init : function(editor)
42210 this.editor = editor;
42213 var fid = editor.frameId;
42215 function btn(id, toggle, handler){
42216 var xid = fid + '-'+ id ;
42220 cls : 'x-btn-icon x-edit-'+id,
42221 enableToggle:toggle !== false,
42222 scope: editor, // was editor...
42223 handler:handler||editor.relayBtnCmd,
42224 clickEvent:'mousedown',
42225 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42229 // create a new element.
42230 var wdiv = editor.wrap.createChild({
42232 }, editor.wrap.dom.firstChild.nextSibling, true);
42234 // can we do this more than once??
42236 // stop form submits
42239 // disable everything...
42240 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42241 this.toolbars = {};
42243 for (var i in ty) {
42245 this.toolbars[i] = this.buildToolbar(ty[i],i);
42247 this.tb = this.toolbars.BODY;
42249 this.buildFooter();
42250 this.footer.show();
42251 editor.on('hide', function( ) { this.footer.hide() }, this);
42252 editor.on('show', function( ) { this.footer.show() }, this);
42255 this.rendered = true;
42257 // the all the btns;
42258 editor.on('editorevent', this.updateToolbar, this);
42259 // other toolbars need to implement this..
42260 //editor.on('editmodechange', this.updateToolbar, this);
42266 * Protected method that will not generally be called directly. It triggers
42267 * a toolbar update by reading the markup state of the current selection in the editor.
42269 updateToolbar: function(editor,ev,sel){
42272 // capture mouse up - this is handy for selecting images..
42273 // perhaps should go somewhere else...
42274 if(!this.editor.activated){
42275 this.editor.onFirstFocus();
42279 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
42280 // selectNode - might want to handle IE?
42282 (ev.type == 'mouseup' || ev.type == 'click' ) &&
42283 ev.target && ev.target.tagName == 'IMG') {
42284 // they have click on an image...
42285 // let's see if we can change the selection...
42288 var nodeRange = sel.ownerDocument.createRange();
42290 nodeRange.selectNode(sel);
42292 nodeRange.selectNodeContents(sel);
42294 //nodeRange.collapse(true);
42295 var s = editor.win.getSelection();
42296 s.removeAllRanges();
42297 s.addRange(nodeRange);
42301 var updateFooter = sel ? false : true;
42304 var ans = this.editor.getAllAncestors();
42307 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42310 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
42311 sel = sel ? sel : this.editor.doc.body;
42312 sel = sel.tagName.length ? sel : this.editor.doc.body;
42315 // pick a menu that exists..
42316 var tn = sel.tagName.toUpperCase();
42317 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
42319 tn = sel.tagName.toUpperCase();
42321 var lastSel = this.tb.selectedNode
42323 this.tb.selectedNode = sel;
42325 // if current menu does not match..
42326 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
42329 ///console.log("show: " + tn);
42330 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
42333 this.tb.items.first().el.innerHTML = tn + ': ';
42336 // update attributes
42337 if (this.tb.fields) {
42338 this.tb.fields.each(function(e) {
42339 e.setValue(sel.getAttribute(e.attrname));
42343 var hasStyles = false;
42344 for(var i in this.styles) {
42351 var st = this.tb.fields.item(0);
42353 st.store.removeAll();
42356 var cn = sel.className.split(/\s+/);
42359 if (this.styles['*']) {
42361 Roo.each(this.styles['*'], function(v) {
42362 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42365 if (this.styles[tn]) {
42366 Roo.each(this.styles[tn], function(v) {
42367 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42371 st.store.loadData(avs);
42375 // flag our selected Node.
42376 this.tb.selectedNode = sel;
42379 Roo.menu.MenuMgr.hideAll();
42383 if (!updateFooter) {
42386 // update the footer
42390 this.footerEls = ans.reverse();
42391 Roo.each(this.footerEls, function(a,i) {
42392 if (!a) { return; }
42393 html += html.length ? ' > ' : '';
42395 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
42400 var sz = this.footDisp.up('td').getSize();
42401 this.footDisp.dom.style.width = (sz.width -10) + 'px';
42402 this.footDisp.dom.style.marginLeft = '5px';
42404 this.footDisp.dom.style.overflow = 'hidden';
42406 this.footDisp.dom.innerHTML = html;
42408 //this.editorsyncValue();
42413 onDestroy : function(){
42416 this.tb.items.each(function(item){
42418 item.menu.removeAll();
42420 item.menu.el.destroy();
42428 onFirstFocus: function() {
42429 // need to do this for all the toolbars..
42430 this.tb.items.each(function(item){
42434 buildToolbar: function(tlist, nm)
42436 var editor = this.editor;
42437 // create a new element.
42438 var wdiv = editor.wrap.createChild({
42440 }, editor.wrap.dom.firstChild.nextSibling, true);
42443 var tb = new Roo.Toolbar(wdiv);
42446 tb.add(nm+ ": ");
42449 for(var i in this.styles) {
42454 if (styles && styles.length) {
42456 // this needs a multi-select checkbox...
42457 tb.addField( new Roo.form.ComboBox({
42458 store: new Roo.data.SimpleStore({
42460 fields: ['val', 'selected'],
42463 name : '-roo-edit-className',
42464 attrname : 'className',
42465 displayField:'val',
42469 triggerAction: 'all',
42470 emptyText:'Select Style',
42471 selectOnFocus:true,
42474 'select': function(c, r, i) {
42475 // initial support only for on class per el..
42476 tb.selectedNode.className = r ? r.get('val') : '';
42477 editor.syncValue();
42486 for (var i in tlist) {
42488 var item = tlist[i];
42489 tb.add(item.title + ": ");
42495 // opts == pulldown..
42496 tb.addField( new Roo.form.ComboBox({
42497 store: new Roo.data.SimpleStore({
42502 name : '-roo-edit-' + i,
42504 displayField:'val',
42508 triggerAction: 'all',
42509 emptyText:'Select',
42510 selectOnFocus:true,
42511 width: item.width ? item.width : 130,
42513 'select': function(c, r, i) {
42514 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42523 tb.addField( new Roo.form.TextField({
42526 //allowBlank:false,
42531 tb.addField( new Roo.form.TextField({
42532 name: '-roo-edit-' + i,
42539 'change' : function(f, nv, ov) {
42540 tb.selectedNode.setAttribute(f.attrname, nv);
42546 tb.el.on('click', function(e){
42547 e.preventDefault(); // what does this do?
42549 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42552 // dont need to disable them... as they will get hidden
42557 buildFooter : function()
42560 var fel = this.editor.wrap.createChild();
42561 this.footer = new Roo.Toolbar(fel);
42562 // toolbar has scrolly on left / right?
42563 var footDisp= new Roo.Toolbar.Fill();
42569 handler : function() {
42570 _t.footDisp.scrollTo('left',0,true)
42574 this.footer.add( footDisp );
42579 handler : function() {
42581 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
42585 var fel = Roo.get(footDisp.el);
42586 fel.addClass('x-editor-context');
42587 this.footDispWrap = fel;
42588 this.footDispWrap.overflow = 'hidden';
42590 this.footDisp = fel.createChild();
42591 this.footDispWrap.on('click', this.onContextClick, this)
42595 onContextClick : function (ev,dom)
42597 ev.preventDefault();
42598 var cn = dom.className;
42600 if (!cn.match(/x-ed-loc-/)) {
42603 var n = cn.split('-').pop();
42604 var ans = this.footerEls;
42608 var range = this.editor.createRange();
42610 range.selectNodeContents(sel);
42611 //range.selectNode(sel);
42614 var selection = this.editor.getSelection();
42615 selection.removeAllRanges();
42616 selection.addRange(range);
42620 this.updateToolbar(null, null, sel);
42637 * Ext JS Library 1.1.1
42638 * Copyright(c) 2006-2007, Ext JS, LLC.
42640 * Originally Released Under LGPL - original licence link has changed is not relivant.
42643 * <script type="text/javascript">
42647 * @class Roo.form.BasicForm
42648 * @extends Roo.util.Observable
42649 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
42651 * @param {String/HTMLElement/Roo.Element} el The form element or its id
42652 * @param {Object} config Configuration options
42654 Roo.form.BasicForm = function(el, config){
42655 this.allItems = [];
42656 this.childForms = [];
42657 Roo.apply(this, config);
42659 * The Roo.form.Field items in this form.
42660 * @type MixedCollection
42664 this.items = new Roo.util.MixedCollection(false, function(o){
42665 return o.id || (o.id = Roo.id());
42669 * @event beforeaction
42670 * Fires before any action is performed. Return false to cancel the action.
42671 * @param {Form} this
42672 * @param {Action} action The action to be performed
42674 beforeaction: true,
42676 * @event actionfailed
42677 * Fires when an action fails.
42678 * @param {Form} this
42679 * @param {Action} action The action that failed
42681 actionfailed : true,
42683 * @event actioncomplete
42684 * Fires when an action is completed.
42685 * @param {Form} this
42686 * @param {Action} action The action that completed
42688 actioncomplete : true
42693 Roo.form.BasicForm.superclass.constructor.call(this);
42696 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
42698 * @cfg {String} method
42699 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
42702 * @cfg {DataReader} reader
42703 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
42704 * This is optional as there is built-in support for processing JSON.
42707 * @cfg {DataReader} errorReader
42708 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
42709 * This is completely optional as there is built-in support for processing JSON.
42712 * @cfg {String} url
42713 * The URL to use for form actions if one isn't supplied in the action options.
42716 * @cfg {Boolean} fileUpload
42717 * Set to true if this form is a file upload.
42721 * @cfg {Object} baseParams
42722 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
42727 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
42732 activeAction : null,
42735 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
42736 * or setValues() data instead of when the form was first created.
42738 trackResetOnLoad : false,
42742 * childForms - used for multi-tab forms
42745 childForms : false,
42748 * allItems - full list of fields.
42754 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
42755 * element by passing it or its id or mask the form itself by passing in true.
42758 waitMsgTarget : false,
42761 initEl : function(el){
42762 this.el = Roo.get(el);
42763 this.id = this.el.id || Roo.id();
42764 this.el.on('submit', this.onSubmit, this);
42765 this.el.addClass('x-form');
42769 onSubmit : function(e){
42774 * Returns true if client-side validation on the form is successful.
42777 isValid : function(){
42779 this.items.each(function(f){
42788 * Returns true if any fields in this form have changed since their original load.
42791 isDirty : function(){
42793 this.items.each(function(f){
42803 * Performs a predefined action (submit or load) or custom actions you define on this form.
42804 * @param {String} actionName The name of the action type
42805 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
42806 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
42807 * accept other config options):
42809 Property Type Description
42810 ---------------- --------------- ----------------------------------------------------------------------------------
42811 url String The url for the action (defaults to the form's url)
42812 method String The form method to use (defaults to the form's method, or POST if not defined)
42813 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
42814 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
42815 validate the form on the client (defaults to false)
42817 * @return {BasicForm} this
42819 doAction : function(action, options){
42820 if(typeof action == 'string'){
42821 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
42823 if(this.fireEvent('beforeaction', this, action) !== false){
42824 this.beforeAction(action);
42825 action.run.defer(100, action);
42831 * Shortcut to do a submit action.
42832 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
42833 * @return {BasicForm} this
42835 submit : function(options){
42836 this.doAction('submit', options);
42841 * Shortcut to do a load action.
42842 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
42843 * @return {BasicForm} this
42845 load : function(options){
42846 this.doAction('load', options);
42851 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
42852 * @param {Record} record The record to edit
42853 * @return {BasicForm} this
42855 updateRecord : function(record){
42856 record.beginEdit();
42857 var fs = record.fields;
42858 fs.each(function(f){
42859 var field = this.findField(f.name);
42861 record.set(f.name, field.getValue());
42869 * Loads an Roo.data.Record into this form.
42870 * @param {Record} record The record to load
42871 * @return {BasicForm} this
42873 loadRecord : function(record){
42874 this.setValues(record.data);
42879 beforeAction : function(action){
42880 var o = action.options;
42883 if(this.waitMsgTarget === true){
42884 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
42885 }else if(this.waitMsgTarget){
42886 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
42887 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
42889 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
42895 afterAction : function(action, success){
42896 this.activeAction = null;
42897 var o = action.options;
42899 if(this.waitMsgTarget === true){
42901 }else if(this.waitMsgTarget){
42902 this.waitMsgTarget.unmask();
42904 Roo.MessageBox.updateProgress(1);
42905 Roo.MessageBox.hide();
42912 Roo.callback(o.success, o.scope, [this, action]);
42913 this.fireEvent('actioncomplete', this, action);
42917 // failure condition..
42918 // we have a scenario where updates need confirming.
42919 // eg. if a locking scenario exists..
42920 // we look for { errors : { needs_confirm : true }} in the response.
42922 (typeof(action.result) != 'undefined') &&
42923 (typeof(action.result.errors) != 'undefined') &&
42924 (typeof(action.result.errors.needs_confirm) != 'undefined')
42927 Roo.MessageBox.confirm(
42928 "Change requires confirmation",
42929 action.result.errorMsg,
42934 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
42944 Roo.callback(o.failure, o.scope, [this, action]);
42945 // show an error message if no failed handler is set..
42946 if (!this.hasListener('actionfailed')) {
42947 Roo.MessageBox.alert("Error",
42948 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
42949 action.result.errorMsg :
42950 "Saving Failed, please check your entries or try again"
42954 this.fireEvent('actionfailed', this, action);
42960 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
42961 * @param {String} id The value to search for
42964 findField : function(id){
42965 var field = this.items.get(id);
42967 this.items.each(function(f){
42968 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
42974 return field || null;
42978 * Add a secondary form to this one,
42979 * Used to provide tabbed forms. One form is primary, with hidden values
42980 * which mirror the elements from the other forms.
42982 * @param {Roo.form.Form} form to add.
42985 addForm : function(form)
42988 if (this.childForms.indexOf(form) > -1) {
42992 this.childForms.push(form);
42994 Roo.each(form.allItems, function (fe) {
42996 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
42997 if (this.findField(n)) { // already added..
43000 var add = new Roo.form.Hidden({
43003 add.render(this.el);
43010 * Mark fields in this form invalid in bulk.
43011 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43012 * @return {BasicForm} this
43014 markInvalid : function(errors){
43015 if(errors instanceof Array){
43016 for(var i = 0, len = errors.length; i < len; i++){
43017 var fieldError = errors[i];
43018 var f = this.findField(fieldError.id);
43020 f.markInvalid(fieldError.msg);
43026 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43027 field.markInvalid(errors[id]);
43031 Roo.each(this.childForms || [], function (f) {
43032 f.markInvalid(errors);
43039 * Set values for fields in this form in bulk.
43040 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43041 * @return {BasicForm} this
43043 setValues : function(values){
43044 if(values instanceof Array){ // array of objects
43045 for(var i = 0, len = values.length; i < len; i++){
43047 var f = this.findField(v.id);
43049 f.setValue(v.value);
43050 if(this.trackResetOnLoad){
43051 f.originalValue = f.getValue();
43055 }else{ // object hash
43058 if(typeof values[id] != 'function' && (field = this.findField(id))){
43060 if (field.setFromData &&
43061 field.valueField &&
43062 field.displayField &&
43063 // combos' with local stores can
43064 // be queried via setValue()
43065 // to set their value..
43066 (field.store && !field.store.isLocal)
43070 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
43071 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
43072 field.setFromData(sd);
43075 field.setValue(values[id]);
43079 if(this.trackResetOnLoad){
43080 field.originalValue = field.getValue();
43086 Roo.each(this.childForms || [], function (f) {
43087 f.setValues(values);
43094 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
43095 * they are returned as an array.
43096 * @param {Boolean} asString
43099 getValues : function(asString){
43100 if (this.childForms) {
43101 // copy values from the child forms
43102 Roo.each(this.childForms, function (f) {
43103 this.setValues(f.getValues());
43109 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
43110 if(asString === true){
43113 return Roo.urlDecode(fs);
43117 * Returns the fields in this form as an object with key/value pairs.
43118 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
43121 getFieldValues : function(with_hidden)
43123 if (this.childForms) {
43124 // copy values from the child forms
43125 // should this call getFieldValues - probably not as we do not currently copy
43126 // hidden fields when we generate..
43127 Roo.each(this.childForms, function (f) {
43128 this.setValues(f.getValues());
43133 this.items.each(function(f){
43134 if (!f.getName()) {
43137 var v = f.getValue();
43138 // not sure if this supported any more..
43139 if ((typeof(v) == 'object') && f.getRawValue) {
43140 v = f.getRawValue() ; // dates..
43142 // combo boxes where name != hiddenName...
43143 if (f.name != f.getName()) {
43144 ret[f.name] = f.getRawValue();
43146 ret[f.getName()] = v;
43153 * Clears all invalid messages in this form.
43154 * @return {BasicForm} this
43156 clearInvalid : function(){
43157 this.items.each(function(f){
43161 Roo.each(this.childForms || [], function (f) {
43170 * Resets this form.
43171 * @return {BasicForm} this
43173 reset : function(){
43174 this.items.each(function(f){
43178 Roo.each(this.childForms || [], function (f) {
43187 * Add Roo.form components to this form.
43188 * @param {Field} field1
43189 * @param {Field} field2 (optional)
43190 * @param {Field} etc (optional)
43191 * @return {BasicForm} this
43194 this.items.addAll(Array.prototype.slice.call(arguments, 0));
43200 * Removes a field from the items collection (does NOT remove its markup).
43201 * @param {Field} field
43202 * @return {BasicForm} this
43204 remove : function(field){
43205 this.items.remove(field);
43210 * Looks at the fields in this form, checks them for an id attribute,
43211 * and calls applyTo on the existing dom element with that id.
43212 * @return {BasicForm} this
43214 render : function(){
43215 this.items.each(function(f){
43216 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
43224 * Calls {@link Ext#apply} for all fields in this form with the passed object.
43225 * @param {Object} values
43226 * @return {BasicForm} this
43228 applyToFields : function(o){
43229 this.items.each(function(f){
43236 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
43237 * @param {Object} values
43238 * @return {BasicForm} this
43240 applyIfToFields : function(o){
43241 this.items.each(function(f){
43249 Roo.BasicForm = Roo.form.BasicForm;/*
43251 * Ext JS Library 1.1.1
43252 * Copyright(c) 2006-2007, Ext JS, LLC.
43254 * Originally Released Under LGPL - original licence link has changed is not relivant.
43257 * <script type="text/javascript">
43261 * @class Roo.form.Form
43262 * @extends Roo.form.BasicForm
43263 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
43265 * @param {Object} config Configuration options
43267 Roo.form.Form = function(config){
43269 if (config.items) {
43270 xitems = config.items;
43271 delete config.items;
43275 Roo.form.Form.superclass.constructor.call(this, null, config);
43276 this.url = this.url || this.action;
43278 this.root = new Roo.form.Layout(Roo.applyIf({
43282 this.active = this.root;
43284 * Array of all the buttons that have been added to this form via {@link addButton}
43288 this.allItems = [];
43291 * @event clientvalidation
43292 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
43293 * @param {Form} this
43294 * @param {Boolean} valid true if the form has passed client-side validation
43296 clientvalidation: true,
43299 * Fires when the form is rendered
43300 * @param {Roo.form.Form} form
43305 if (this.progressUrl) {
43306 // push a hidden field onto the list of fields..
43310 name : 'UPLOAD_IDENTIFIER'
43315 Roo.each(xitems, this.addxtype, this);
43321 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
43323 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
43326 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
43329 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
43331 buttonAlign:'center',
43334 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
43339 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
43340 * This property cascades to child containers if not set.
43345 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
43346 * fires a looping event with that state. This is required to bind buttons to the valid
43347 * state using the config value formBind:true on the button.
43349 monitorValid : false,
43352 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
43357 * @cfg {String} progressUrl - Url to return progress data
43360 progressUrl : false,
43363 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
43364 * fields are added and the column is closed. If no fields are passed the column remains open
43365 * until end() is called.
43366 * @param {Object} config The config to pass to the column
43367 * @param {Field} field1 (optional)
43368 * @param {Field} field2 (optional)
43369 * @param {Field} etc (optional)
43370 * @return Column The column container object
43372 column : function(c){
43373 var col = new Roo.form.Column(c);
43375 if(arguments.length > 1){ // duplicate code required because of Opera
43376 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43383 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
43384 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
43385 * until end() is called.
43386 * @param {Object} config The config to pass to the fieldset
43387 * @param {Field} field1 (optional)
43388 * @param {Field} field2 (optional)
43389 * @param {Field} etc (optional)
43390 * @return FieldSet The fieldset container object
43392 fieldset : function(c){
43393 var fs = new Roo.form.FieldSet(c);
43395 if(arguments.length > 1){ // duplicate code required because of Opera
43396 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43403 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
43404 * fields are added and the container is closed. If no fields are passed the container remains open
43405 * until end() is called.
43406 * @param {Object} config The config to pass to the Layout
43407 * @param {Field} field1 (optional)
43408 * @param {Field} field2 (optional)
43409 * @param {Field} etc (optional)
43410 * @return Layout The container object
43412 container : function(c){
43413 var l = new Roo.form.Layout(c);
43415 if(arguments.length > 1){ // duplicate code required because of Opera
43416 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43423 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
43424 * @param {Object} container A Roo.form.Layout or subclass of Layout
43425 * @return {Form} this
43427 start : function(c){
43428 // cascade label info
43429 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43430 this.active.stack.push(c);
43431 c.ownerCt = this.active;
43437 * Closes the current open container
43438 * @return {Form} this
43441 if(this.active == this.root){
43444 this.active = this.active.ownerCt;
43449 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43450 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43451 * as the label of the field.
43452 * @param {Field} field1
43453 * @param {Field} field2 (optional)
43454 * @param {Field} etc. (optional)
43455 * @return {Form} this
43458 this.active.stack.push.apply(this.active.stack, arguments);
43459 this.allItems.push.apply(this.allItems,arguments);
43461 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43462 if(a[i].isFormField){
43467 Roo.form.Form.superclass.add.apply(this, r);
43477 * Find any element that has been added to a form, using it's ID or name
43478 * This can include framesets, columns etc. along with regular fields..
43479 * @param {String} id - id or name to find.
43481 * @return {Element} e - or false if nothing found.
43483 findbyId : function(id)
43489 Roo.each(this.allItems, function(f){
43490 if (f.id == id || f.name == id ){
43501 * Render this form into the passed container. This should only be called once!
43502 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43503 * @return {Form} this
43505 render : function(ct)
43511 var o = this.autoCreate || {
43513 method : this.method || 'POST',
43514 id : this.id || Roo.id()
43516 this.initEl(ct.createChild(o));
43518 this.root.render(this.el);
43522 this.items.each(function(f){
43523 f.render('x-form-el-'+f.id);
43526 if(this.buttons.length > 0){
43527 // tables are required to maintain order and for correct IE layout
43528 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43529 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43530 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43532 var tr = tb.getElementsByTagName('tr')[0];
43533 for(var i = 0, len = this.buttons.length; i < len; i++) {
43534 var b = this.buttons[i];
43535 var td = document.createElement('td');
43536 td.className = 'x-form-btn-td';
43537 b.render(tr.appendChild(td));
43540 if(this.monitorValid){ // initialize after render
43541 this.startMonitoring();
43543 this.fireEvent('rendered', this);
43548 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43549 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43550 * object or a valid Roo.DomHelper element config
43551 * @param {Function} handler The function called when the button is clicked
43552 * @param {Object} scope (optional) The scope of the handler function
43553 * @return {Roo.Button}
43555 addButton : function(config, handler, scope){
43559 minWidth: this.minButtonWidth,
43562 if(typeof config == "string"){
43565 Roo.apply(bc, config);
43567 var btn = new Roo.Button(null, bc);
43568 this.buttons.push(btn);
43573 * Adds a series of form elements (using the xtype property as the factory method.
43574 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
43575 * @param {Object} config
43578 addxtype : function()
43580 var ar = Array.prototype.slice.call(arguments, 0);
43582 for(var i = 0; i < ar.length; i++) {
43584 continue; // skip -- if this happends something invalid got sent, we
43585 // should ignore it, as basically that interface element will not show up
43586 // and that should be pretty obvious!!
43589 if (Roo.form[ar[i].xtype]) {
43591 var fe = Roo.factory(ar[i], Roo.form);
43597 fe.store.form = this;
43602 this.allItems.push(fe);
43603 if (fe.items && fe.addxtype) {
43604 fe.addxtype.apply(fe, fe.items);
43614 // console.log('adding ' + ar[i].xtype);
43616 if (ar[i].xtype == 'Button') {
43617 //console.log('adding button');
43618 //console.log(ar[i]);
43619 this.addButton(ar[i]);
43620 this.allItems.push(fe);
43624 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
43625 alert('end is not supported on xtype any more, use items');
43627 // //console.log('adding end');
43635 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
43636 * option "monitorValid"
43638 startMonitoring : function(){
43641 Roo.TaskMgr.start({
43642 run : this.bindHandler,
43643 interval : this.monitorPoll || 200,
43650 * Stops monitoring of the valid state of this form
43652 stopMonitoring : function(){
43653 this.bound = false;
43657 bindHandler : function(){
43659 return false; // stops binding
43662 this.items.each(function(f){
43663 if(!f.isValid(true)){
43668 for(var i = 0, len = this.buttons.length; i < len; i++){
43669 var btn = this.buttons[i];
43670 if(btn.formBind === true && btn.disabled === valid){
43671 btn.setDisabled(!valid);
43674 this.fireEvent('clientvalidation', this, valid);
43688 Roo.Form = Roo.form.Form;
43691 * Ext JS Library 1.1.1
43692 * Copyright(c) 2006-2007, Ext JS, LLC.
43694 * Originally Released Under LGPL - original licence link has changed is not relivant.
43697 * <script type="text/javascript">
43701 * @class Roo.form.Action
43702 * Internal Class used to handle form actions
43704 * @param {Roo.form.BasicForm} el The form element or its id
43705 * @param {Object} config Configuration options
43709 // define the action interface
43710 Roo.form.Action = function(form, options){
43712 this.options = options || {};
43715 * Client Validation Failed
43718 Roo.form.Action.CLIENT_INVALID = 'client';
43720 * Server Validation Failed
43723 Roo.form.Action.SERVER_INVALID = 'server';
43725 * Connect to Server Failed
43728 Roo.form.Action.CONNECT_FAILURE = 'connect';
43730 * Reading Data from Server Failed
43733 Roo.form.Action.LOAD_FAILURE = 'load';
43735 Roo.form.Action.prototype = {
43737 failureType : undefined,
43738 response : undefined,
43739 result : undefined,
43741 // interface method
43742 run : function(options){
43746 // interface method
43747 success : function(response){
43751 // interface method
43752 handleResponse : function(response){
43756 // default connection failure
43757 failure : function(response){
43759 this.response = response;
43760 this.failureType = Roo.form.Action.CONNECT_FAILURE;
43761 this.form.afterAction(this, false);
43764 processResponse : function(response){
43765 this.response = response;
43766 if(!response.responseText){
43769 this.result = this.handleResponse(response);
43770 return this.result;
43773 // utility functions used internally
43774 getUrl : function(appendParams){
43775 var url = this.options.url || this.form.url || this.form.el.dom.action;
43777 var p = this.getParams();
43779 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
43785 getMethod : function(){
43786 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
43789 getParams : function(){
43790 var bp = this.form.baseParams;
43791 var p = this.options.params;
43793 if(typeof p == "object"){
43794 p = Roo.urlEncode(Roo.applyIf(p, bp));
43795 }else if(typeof p == 'string' && bp){
43796 p += '&' + Roo.urlEncode(bp);
43799 p = Roo.urlEncode(bp);
43804 createCallback : function(){
43806 success: this.success,
43807 failure: this.failure,
43809 timeout: (this.form.timeout*1000),
43810 upload: this.form.fileUpload ? this.success : undefined
43815 Roo.form.Action.Submit = function(form, options){
43816 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
43819 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
43822 haveProgress : false,
43823 uploadComplete : false,
43825 // uploadProgress indicator.
43826 uploadProgress : function()
43828 if (!this.form.progressUrl) {
43832 if (!this.haveProgress) {
43833 Roo.MessageBox.progress("Uploading", "Uploading");
43835 if (this.uploadComplete) {
43836 Roo.MessageBox.hide();
43840 this.haveProgress = true;
43842 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
43844 var c = new Roo.data.Connection();
43846 url : this.form.progressUrl,
43851 success : function(req){
43852 //console.log(data);
43856 rdata = Roo.decode(req.responseText)
43858 Roo.log("Invalid data from server..");
43862 if (!rdata || !rdata.success) {
43864 Roo.MessageBox.alert(Roo.encode(rdata));
43867 var data = rdata.data;
43869 if (this.uploadComplete) {
43870 Roo.MessageBox.hide();
43875 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
43876 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
43879 this.uploadProgress.defer(2000,this);
43882 failure: function(data) {
43883 Roo.log('progress url failed ');
43894 // run get Values on the form, so it syncs any secondary forms.
43895 this.form.getValues();
43897 var o = this.options;
43898 var method = this.getMethod();
43899 var isPost = method == 'POST';
43900 if(o.clientValidation === false || this.form.isValid()){
43902 if (this.form.progressUrl) {
43903 this.form.findField('UPLOAD_IDENTIFIER').setValue(
43904 (new Date() * 1) + '' + Math.random());
43909 Roo.Ajax.request(Roo.apply(this.createCallback(), {
43910 form:this.form.el.dom,
43911 url:this.getUrl(!isPost),
43913 params:isPost ? this.getParams() : null,
43914 isUpload: this.form.fileUpload
43917 this.uploadProgress();
43919 }else if (o.clientValidation !== false){ // client validation failed
43920 this.failureType = Roo.form.Action.CLIENT_INVALID;
43921 this.form.afterAction(this, false);
43925 success : function(response)
43927 this.uploadComplete= true;
43928 if (this.haveProgress) {
43929 Roo.MessageBox.hide();
43933 var result = this.processResponse(response);
43934 if(result === true || result.success){
43935 this.form.afterAction(this, true);
43939 this.form.markInvalid(result.errors);
43940 this.failureType = Roo.form.Action.SERVER_INVALID;
43942 this.form.afterAction(this, false);
43944 failure : function(response)
43946 this.uploadComplete= true;
43947 if (this.haveProgress) {
43948 Roo.MessageBox.hide();
43951 this.response = response;
43952 this.failureType = Roo.form.Action.CONNECT_FAILURE;
43953 this.form.afterAction(this, false);
43956 handleResponse : function(response){
43957 if(this.form.errorReader){
43958 var rs = this.form.errorReader.read(response);
43961 for(var i = 0, len = rs.records.length; i < len; i++) {
43962 var r = rs.records[i];
43963 errors[i] = r.data;
43966 if(errors.length < 1){
43970 success : rs.success,
43976 ret = Roo.decode(response.responseText);
43980 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
43990 Roo.form.Action.Load = function(form, options){
43991 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
43992 this.reader = this.form.reader;
43995 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44000 Roo.Ajax.request(Roo.apply(
44001 this.createCallback(), {
44002 method:this.getMethod(),
44003 url:this.getUrl(false),
44004 params:this.getParams()
44008 success : function(response){
44010 var result = this.processResponse(response);
44011 if(result === true || !result.success || !result.data){
44012 this.failureType = Roo.form.Action.LOAD_FAILURE;
44013 this.form.afterAction(this, false);
44016 this.form.clearInvalid();
44017 this.form.setValues(result.data);
44018 this.form.afterAction(this, true);
44021 handleResponse : function(response){
44022 if(this.form.reader){
44023 var rs = this.form.reader.read(response);
44024 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44026 success : rs.success,
44030 return Roo.decode(response.responseText);
44034 Roo.form.Action.ACTION_TYPES = {
44035 'load' : Roo.form.Action.Load,
44036 'submit' : Roo.form.Action.Submit
44039 * Ext JS Library 1.1.1
44040 * Copyright(c) 2006-2007, Ext JS, LLC.
44042 * Originally Released Under LGPL - original licence link has changed is not relivant.
44045 * <script type="text/javascript">
44049 * @class Roo.form.Layout
44050 * @extends Roo.Component
44051 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
44053 * @param {Object} config Configuration options
44055 Roo.form.Layout = function(config){
44057 if (config.items) {
44058 xitems = config.items;
44059 delete config.items;
44061 Roo.form.Layout.superclass.constructor.call(this, config);
44063 Roo.each(xitems, this.addxtype, this);
44067 Roo.extend(Roo.form.Layout, Roo.Component, {
44069 * @cfg {String/Object} autoCreate
44070 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
44073 * @cfg {String/Object/Function} style
44074 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
44075 * a function which returns such a specification.
44078 * @cfg {String} labelAlign
44079 * Valid values are "left," "top" and "right" (defaults to "left")
44082 * @cfg {Number} labelWidth
44083 * Fixed width in pixels of all field labels (defaults to undefined)
44086 * @cfg {Boolean} clear
44087 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
44091 * @cfg {String} labelSeparator
44092 * The separator to use after field labels (defaults to ':')
44094 labelSeparator : ':',
44096 * @cfg {Boolean} hideLabels
44097 * True to suppress the display of field labels in this layout (defaults to false)
44099 hideLabels : false,
44102 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
44107 onRender : function(ct, position){
44108 if(this.el){ // from markup
44109 this.el = Roo.get(this.el);
44110 }else { // generate
44111 var cfg = this.getAutoCreate();
44112 this.el = ct.createChild(cfg, position);
44115 this.el.applyStyles(this.style);
44117 if(this.labelAlign){
44118 this.el.addClass('x-form-label-'+this.labelAlign);
44120 if(this.hideLabels){
44121 this.labelStyle = "display:none";
44122 this.elementStyle = "padding-left:0;";
44124 if(typeof this.labelWidth == 'number'){
44125 this.labelStyle = "width:"+this.labelWidth+"px;";
44126 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
44128 if(this.labelAlign == 'top'){
44129 this.labelStyle = "width:auto;";
44130 this.elementStyle = "padding-left:0;";
44133 var stack = this.stack;
44134 var slen = stack.length;
44136 if(!this.fieldTpl){
44137 var t = new Roo.Template(
44138 '<div class="x-form-item {5}">',
44139 '<label for="{0}" style="{2}">{1}{4}</label>',
44140 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44142 '</div><div class="x-form-clear-left"></div>'
44144 t.disableFormats = true;
44146 Roo.form.Layout.prototype.fieldTpl = t;
44148 for(var i = 0; i < slen; i++) {
44149 if(stack[i].isFormField){
44150 this.renderField(stack[i]);
44152 this.renderComponent(stack[i]);
44157 this.el.createChild({cls:'x-form-clear'});
44162 renderField : function(f){
44163 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
44166 f.labelStyle||this.labelStyle||'', //2
44167 this.elementStyle||'', //3
44168 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
44169 f.itemCls||this.itemCls||'' //5
44170 ], true).getPrevSibling());
44174 renderComponent : function(c){
44175 c.render(c.isLayout ? this.el : this.el.createChild());
44178 * Adds a object form elements (using the xtype property as the factory method.)
44179 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
44180 * @param {Object} config
44182 addxtype : function(o)
44184 // create the lement.
44185 o.form = this.form;
44186 var fe = Roo.factory(o, Roo.form);
44187 this.form.allItems.push(fe);
44188 this.stack.push(fe);
44190 if (fe.isFormField) {
44191 this.form.items.add(fe);
44199 * @class Roo.form.Column
44200 * @extends Roo.form.Layout
44201 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
44203 * @param {Object} config Configuration options
44205 Roo.form.Column = function(config){
44206 Roo.form.Column.superclass.constructor.call(this, config);
44209 Roo.extend(Roo.form.Column, Roo.form.Layout, {
44211 * @cfg {Number/String} width
44212 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44215 * @cfg {String/Object} autoCreate
44216 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
44220 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
44223 onRender : function(ct, position){
44224 Roo.form.Column.superclass.onRender.call(this, ct, position);
44226 this.el.setWidth(this.width);
44233 * @class Roo.form.Row
44234 * @extends Roo.form.Layout
44235 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
44237 * @param {Object} config Configuration options
44241 Roo.form.Row = function(config){
44242 Roo.form.Row.superclass.constructor.call(this, config);
44245 Roo.extend(Roo.form.Row, Roo.form.Layout, {
44247 * @cfg {Number/String} width
44248 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44251 * @cfg {Number/String} height
44252 * The fixed height of the column in pixels or CSS value (defaults to "auto")
44254 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
44258 onRender : function(ct, position){
44259 //console.log('row render');
44261 var t = new Roo.Template(
44262 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
44263 '<label for="{0}" style="{2}">{1}{4}</label>',
44264 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44268 t.disableFormats = true;
44270 Roo.form.Layout.prototype.rowTpl = t;
44272 this.fieldTpl = this.rowTpl;
44274 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
44275 var labelWidth = 100;
44277 if ((this.labelAlign != 'top')) {
44278 if (typeof this.labelWidth == 'number') {
44279 labelWidth = this.labelWidth
44281 this.padWidth = 20 + labelWidth;
44285 Roo.form.Column.superclass.onRender.call(this, ct, position);
44287 this.el.setWidth(this.width);
44290 this.el.setHeight(this.height);
44295 renderField : function(f){
44296 f.fieldEl = this.fieldTpl.append(this.el, [
44297 f.id, f.fieldLabel,
44298 f.labelStyle||this.labelStyle||'',
44299 this.elementStyle||'',
44300 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
44301 f.itemCls||this.itemCls||'',
44302 f.width ? f.width + this.padWidth : 160 + this.padWidth
44309 * @class Roo.form.FieldSet
44310 * @extends Roo.form.Layout
44311 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
44313 * @param {Object} config Configuration options
44315 Roo.form.FieldSet = function(config){
44316 Roo.form.FieldSet.superclass.constructor.call(this, config);
44319 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
44321 * @cfg {String} legend
44322 * The text to display as the legend for the FieldSet (defaults to '')
44325 * @cfg {String/Object} autoCreate
44326 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
44330 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
44333 onRender : function(ct, position){
44334 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
44336 this.setLegend(this.legend);
44341 setLegend : function(text){
44343 this.el.child('legend').update(text);
44348 * Ext JS Library 1.1.1
44349 * Copyright(c) 2006-2007, Ext JS, LLC.
44351 * Originally Released Under LGPL - original licence link has changed is not relivant.
44354 * <script type="text/javascript">
44357 * @class Roo.form.VTypes
44358 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
44361 Roo.form.VTypes = function(){
44362 // closure these in so they are only created once.
44363 var alpha = /^[a-zA-Z_]+$/;
44364 var alphanum = /^[a-zA-Z0-9_]+$/;
44365 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
44366 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
44368 // All these messages and functions are configurable
44371 * The function used to validate email addresses
44372 * @param {String} value The email address
44374 'email' : function(v){
44375 return email.test(v);
44378 * The error text to display when the email validation function returns false
44381 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
44383 * The keystroke filter mask to be applied on email input
44386 'emailMask' : /[a-z0-9_\.\-@]/i,
44389 * The function used to validate URLs
44390 * @param {String} value The URL
44392 'url' : function(v){
44393 return url.test(v);
44396 * The error text to display when the url validation function returns false
44399 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
44402 * The function used to validate alpha values
44403 * @param {String} value The value
44405 'alpha' : function(v){
44406 return alpha.test(v);
44409 * The error text to display when the alpha validation function returns false
44412 'alphaText' : 'This field should only contain letters and _',
44414 * The keystroke filter mask to be applied on alpha input
44417 'alphaMask' : /[a-z_]/i,
44420 * The function used to validate alphanumeric values
44421 * @param {String} value The value
44423 'alphanum' : function(v){
44424 return alphanum.test(v);
44427 * The error text to display when the alphanumeric validation function returns false
44430 'alphanumText' : 'This field should only contain letters, numbers and _',
44432 * The keystroke filter mask to be applied on alphanumeric input
44435 'alphanumMask' : /[a-z0-9_]/i
44437 }();//<script type="text/javascript">
44440 * @class Roo.form.FCKeditor
44441 * @extends Roo.form.TextArea
44442 * Wrapper around the FCKEditor http://www.fckeditor.net
44444 * Creates a new FCKeditor
44445 * @param {Object} config Configuration options
44447 Roo.form.FCKeditor = function(config){
44448 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44451 * @event editorinit
44452 * Fired when the editor is initialized - you can add extra handlers here..
44453 * @param {FCKeditor} this
44454 * @param {Object} the FCK object.
44461 Roo.form.FCKeditor.editors = { };
44462 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44464 //defaultAutoCreate : {
44465 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44469 * @cfg {Object} fck options - see fck manual for details.
44474 * @cfg {Object} fck toolbar set (Basic or Default)
44476 toolbarSet : 'Basic',
44478 * @cfg {Object} fck BasePath
44480 basePath : '/fckeditor/',
44488 onRender : function(ct, position)
44491 this.defaultAutoCreate = {
44493 style:"width:300px;height:60px;",
44494 autocomplete: "off"
44497 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44500 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44501 if(this.preventScrollbars){
44502 this.el.setStyle("overflow", "hidden");
44504 this.el.setHeight(this.growMin);
44507 //console.log('onrender' + this.getId() );
44508 Roo.form.FCKeditor.editors[this.getId()] = this;
44511 this.replaceTextarea() ;
44515 getEditor : function() {
44516 return this.fckEditor;
44519 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44520 * @param {Mixed} value The value to set
44524 setValue : function(value)
44526 //console.log('setValue: ' + value);
44528 if(typeof(value) == 'undefined') { // not sure why this is happending...
44531 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44533 //if(!this.el || !this.getEditor()) {
44534 // this.value = value;
44535 //this.setValue.defer(100,this,[value]);
44539 if(!this.getEditor()) {
44543 this.getEditor().SetData(value);
44550 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44551 * @return {Mixed} value The field value
44553 getValue : function()
44556 if (this.frame && this.frame.dom.style.display == 'none') {
44557 return Roo.form.FCKeditor.superclass.getValue.call(this);
44560 if(!this.el || !this.getEditor()) {
44562 // this.getValue.defer(100,this);
44567 var value=this.getEditor().GetData();
44568 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44569 return Roo.form.FCKeditor.superclass.getValue.call(this);
44575 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
44576 * @return {Mixed} value The field value
44578 getRawValue : function()
44580 if (this.frame && this.frame.dom.style.display == 'none') {
44581 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44584 if(!this.el || !this.getEditor()) {
44585 //this.getRawValue.defer(100,this);
44592 var value=this.getEditor().GetData();
44593 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
44594 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44598 setSize : function(w,h) {
44602 //if (this.frame && this.frame.dom.style.display == 'none') {
44603 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44606 //if(!this.el || !this.getEditor()) {
44607 // this.setSize.defer(100,this, [w,h]);
44613 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44615 this.frame.dom.setAttribute('width', w);
44616 this.frame.dom.setAttribute('height', h);
44617 this.frame.setSize(w,h);
44621 toggleSourceEdit : function(value) {
44625 this.el.dom.style.display = value ? '' : 'none';
44626 this.frame.dom.style.display = value ? 'none' : '';
44631 focus: function(tag)
44633 if (this.frame.dom.style.display == 'none') {
44634 return Roo.form.FCKeditor.superclass.focus.call(this);
44636 if(!this.el || !this.getEditor()) {
44637 this.focus.defer(100,this, [tag]);
44644 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
44645 this.getEditor().Focus();
44647 if (!this.getEditor().Selection.GetSelection()) {
44648 this.focus.defer(100,this, [tag]);
44653 var r = this.getEditor().EditorDocument.createRange();
44654 r.setStart(tgs[0],0);
44655 r.setEnd(tgs[0],0);
44656 this.getEditor().Selection.GetSelection().removeAllRanges();
44657 this.getEditor().Selection.GetSelection().addRange(r);
44658 this.getEditor().Focus();
44665 replaceTextarea : function()
44667 if ( document.getElementById( this.getId() + '___Frame' ) )
44669 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
44671 // We must check the elements firstly using the Id and then the name.
44672 var oTextarea = document.getElementById( this.getId() );
44674 var colElementsByName = document.getElementsByName( this.getId() ) ;
44676 oTextarea.style.display = 'none' ;
44678 if ( oTextarea.tabIndex ) {
44679 this.TabIndex = oTextarea.tabIndex ;
44682 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
44683 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
44684 this.frame = Roo.get(this.getId() + '___Frame')
44687 _getConfigHtml : function()
44691 for ( var o in this.fckconfig ) {
44692 sConfig += sConfig.length > 0 ? '&' : '';
44693 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
44696 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
44700 _getIFrameHtml : function()
44702 var sFile = 'fckeditor.html' ;
44703 /* no idea what this is about..
44706 if ( (/fcksource=true/i).test( window.top.location.search ) )
44707 sFile = 'fckeditor.original.html' ;
44712 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
44713 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
44716 var html = '<iframe id="' + this.getId() +
44717 '___Frame" src="' + sLink +
44718 '" width="' + this.width +
44719 '" height="' + this.height + '"' +
44720 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
44721 ' frameborder="0" scrolling="no"></iframe>' ;
44726 _insertHtmlBefore : function( html, element )
44728 if ( element.insertAdjacentHTML ) {
44730 element.insertAdjacentHTML( 'beforeBegin', html ) ;
44732 var oRange = document.createRange() ;
44733 oRange.setStartBefore( element ) ;
44734 var oFragment = oRange.createContextualFragment( html );
44735 element.parentNode.insertBefore( oFragment, element ) ;
44748 //Roo.reg('fckeditor', Roo.form.FCKeditor);
44750 function FCKeditor_OnComplete(editorInstance){
44751 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
44752 f.fckEditor = editorInstance;
44753 //console.log("loaded");
44754 f.fireEvent('editorinit', f, editorInstance);
44774 //<script type="text/javascript">
44776 * @class Roo.form.GridField
44777 * @extends Roo.form.Field
44778 * Embed a grid (or editable grid into a form)
44781 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
44783 * xgrid.store = Roo.data.Store
44784 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
44785 * xgrid.store.reader = Roo.data.JsonReader
44789 * Creates a new GridField
44790 * @param {Object} config Configuration options
44792 Roo.form.GridField = function(config){
44793 Roo.form.GridField.superclass.constructor.call(this, config);
44797 Roo.extend(Roo.form.GridField, Roo.form.Field, {
44799 * @cfg {Number} width - used to restrict width of grid..
44803 * @cfg {Number} height - used to restrict height of grid..
44807 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
44813 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44814 * {tag: "input", type: "checkbox", autocomplete: "off"})
44816 // defaultAutoCreate : { tag: 'div' },
44817 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
44819 * @cfg {String} addTitle Text to include for adding a title.
44823 onResize : function(){
44824 Roo.form.Field.superclass.onResize.apply(this, arguments);
44827 initEvents : function(){
44828 // Roo.form.Checkbox.superclass.initEvents.call(this);
44829 // has no events...
44834 getResizeEl : function(){
44838 getPositionEl : function(){
44843 onRender : function(ct, position){
44845 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
44846 var style = this.style;
44849 Roo.form.GridField.superclass.onRender.call(this, ct, position);
44850 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
44851 this.viewEl = this.wrap.createChild({ tag: 'div' });
44853 this.viewEl.applyStyles(style);
44856 this.viewEl.setWidth(this.width);
44859 this.viewEl.setHeight(this.height);
44861 //if(this.inputValue !== undefined){
44862 //this.setValue(this.value);
44865 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
44868 this.grid.render();
44869 this.grid.getDataSource().on('remove', this.refreshValue, this);
44870 this.grid.getDataSource().on('update', this.refreshValue, this);
44871 this.grid.on('afteredit', this.refreshValue, this);
44877 * Sets the value of the item.
44878 * @param {String} either an object or a string..
44880 setValue : function(v){
44882 v = v || []; // empty set..
44883 // this does not seem smart - it really only affects memoryproxy grids..
44884 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
44885 var ds = this.grid.getDataSource();
44886 // assumes a json reader..
44888 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
44889 ds.loadData( data);
44891 // clear selection so it does not get stale.
44892 if (this.grid.sm) {
44893 this.grid.sm.clearSelections();
44896 Roo.form.GridField.superclass.setValue.call(this, v);
44897 this.refreshValue();
44898 // should load data in the grid really....
44902 refreshValue: function() {
44904 this.grid.getDataSource().each(function(r) {
44907 this.el.dom.value = Roo.encode(val);
44915 * Ext JS Library 1.1.1
44916 * Copyright(c) 2006-2007, Ext JS, LLC.
44918 * Originally Released Under LGPL - original licence link has changed is not relivant.
44921 * <script type="text/javascript">
44924 * @class Roo.form.DisplayField
44925 * @extends Roo.form.Field
44926 * A generic Field to display non-editable data.
44928 * Creates a new Display Field item.
44929 * @param {Object} config Configuration options
44931 Roo.form.DisplayField = function(config){
44932 Roo.form.DisplayField.superclass.constructor.call(this, config);
44936 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
44937 inputType: 'hidden',
44943 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44945 focusClass : undefined,
44947 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44949 fieldClass: 'x-form-field',
44952 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
44954 valueRenderer: undefined,
44958 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44959 * {tag: "input", type: "checkbox", autocomplete: "off"})
44962 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
44964 onResize : function(){
44965 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
44969 initEvents : function(){
44970 // Roo.form.Checkbox.superclass.initEvents.call(this);
44971 // has no events...
44976 getResizeEl : function(){
44980 getPositionEl : function(){
44985 onRender : function(ct, position){
44987 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
44988 //if(this.inputValue !== undefined){
44989 this.wrap = this.el.wrap();
44991 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
44993 if (this.bodyStyle) {
44994 this.viewEl.applyStyles(this.bodyStyle);
44996 //this.viewEl.setStyle('padding', '2px');
44998 this.setValue(this.value);
45003 initValue : Roo.emptyFn,
45008 onClick : function(){
45013 * Sets the checked state of the checkbox.
45014 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45016 setValue : function(v){
45018 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45019 // this might be called before we have a dom element..
45020 if (!this.viewEl) {
45023 this.viewEl.dom.innerHTML = html;
45024 Roo.form.DisplayField.superclass.setValue.call(this, v);
45034 * @class Roo.form.DayPicker
45035 * @extends Roo.form.Field
45036 * A Day picker show [M] [T] [W] ....
45038 * Creates a new Day Picker
45039 * @param {Object} config Configuration options
45041 Roo.form.DayPicker= function(config){
45042 Roo.form.DayPicker.superclass.constructor.call(this, config);
45046 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45048 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45050 focusClass : undefined,
45052 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45054 fieldClass: "x-form-field",
45057 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45058 * {tag: "input", type: "checkbox", autocomplete: "off"})
45060 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
45063 actionMode : 'viewEl',
45067 inputType : 'hidden',
45070 inputElement: false, // real input element?
45071 basedOn: false, // ????
45073 isFormField: true, // not sure where this is needed!!!!
45075 onResize : function(){
45076 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
45077 if(!this.boxLabel){
45078 this.el.alignTo(this.wrap, 'c-c');
45082 initEvents : function(){
45083 Roo.form.Checkbox.superclass.initEvents.call(this);
45084 this.el.on("click", this.onClick, this);
45085 this.el.on("change", this.onClick, this);
45089 getResizeEl : function(){
45093 getPositionEl : function(){
45099 onRender : function(ct, position){
45100 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
45102 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
45104 var r1 = '<table><tr>';
45105 var r2 = '<tr class="x-form-daypick-icons">';
45106 for (var i=0; i < 7; i++) {
45107 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
45108 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
45111 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
45112 viewEl.select('img').on('click', this.onClick, this);
45113 this.viewEl = viewEl;
45116 // this will not work on Chrome!!!
45117 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
45118 this.el.on('propertychange', this.setFromHidden, this); //ie
45126 initValue : Roo.emptyFn,
45129 * Returns the checked state of the checkbox.
45130 * @return {Boolean} True if checked, else false
45132 getValue : function(){
45133 return this.el.dom.value;
45138 onClick : function(e){
45139 //this.setChecked(!this.checked);
45140 Roo.get(e.target).toggleClass('x-menu-item-checked');
45141 this.refreshValue();
45142 //if(this.el.dom.checked != this.checked){
45143 // this.setValue(this.el.dom.checked);
45148 refreshValue : function()
45151 this.viewEl.select('img',true).each(function(e,i,n) {
45152 val += e.is(".x-menu-item-checked") ? String(n) : '';
45154 this.setValue(val, true);
45158 * Sets the checked state of the checkbox.
45159 * On is always based on a string comparison between inputValue and the param.
45160 * @param {Boolean/String} value - the value to set
45161 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
45163 setValue : function(v,suppressEvent){
45164 if (!this.el.dom) {
45167 var old = this.el.dom.value ;
45168 this.el.dom.value = v;
45169 if (suppressEvent) {
45173 // update display..
45174 this.viewEl.select('img',true).each(function(e,i,n) {
45176 var on = e.is(".x-menu-item-checked");
45177 var newv = v.indexOf(String(n)) > -1;
45179 e.toggleClass('x-menu-item-checked');
45185 this.fireEvent('change', this, v, old);
45190 // handle setting of hidden value by some other method!!?!?
45191 setFromHidden: function()
45196 //console.log("SET FROM HIDDEN");
45197 //alert('setFrom hidden');
45198 this.setValue(this.el.dom.value);
45201 onDestroy : function()
45204 Roo.get(this.viewEl).remove();
45207 Roo.form.DayPicker.superclass.onDestroy.call(this);
45211 * RooJS Library 1.1.1
45212 * Copyright(c) 2008-2011 Alan Knowles
45219 * @class Roo.form.ComboCheck
45220 * @extends Roo.form.ComboBox
45221 * A combobox for multiple select items.
45223 * FIXME - could do with a reset button..
45226 * Create a new ComboCheck
45227 * @param {Object} config Configuration options
45229 Roo.form.ComboCheck = function(config){
45230 Roo.form.ComboCheck.superclass.constructor.call(this, config);
45231 // should verify some data...
45233 // hiddenName = required..
45234 // displayField = required
45235 // valudField == required
45236 var req= [ 'hiddenName', 'displayField', 'valueField' ];
45238 Roo.each(req, function(e) {
45239 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
45240 throw "Roo.form.ComboCheck : missing value for: " + e;
45247 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
45252 selectedClass: 'x-menu-item-checked',
45255 onRender : function(ct, position){
45261 var cls = 'x-combo-list';
45264 this.tpl = new Roo.Template({
45265 html : '<div class="'+cls+'-item x-menu-check-item">' +
45266 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
45267 '<span>{' + this.displayField + '}</span>' +
45274 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
45275 this.view.singleSelect = false;
45276 this.view.multiSelect = true;
45277 this.view.toggleSelect = true;
45278 this.pageTb.add(new Roo.Toolbar.Fill(), {
45281 handler: function()
45288 onViewOver : function(e, t){
45294 onViewClick : function(doFocus,index){
45298 select: function () {
45299 //Roo.log("SELECT CALLED");
45302 selectByValue : function(xv, scrollIntoView){
45303 var ar = this.getValueArray();
45306 Roo.each(ar, function(v) {
45307 if(v === undefined || v === null){
45310 var r = this.findRecord(this.valueField, v);
45312 sels.push(this.store.indexOf(r))
45316 this.view.select(sels);
45322 onSelect : function(record, index){
45323 // Roo.log("onselect Called");
45324 // this is only called by the clear button now..
45325 this.view.clearSelections();
45326 this.setValue('[]');
45327 if (this.value != this.valueBefore) {
45328 this.fireEvent('change', this, this.value, this.valueBefore);
45331 getValueArray : function()
45336 //Roo.log(this.value);
45337 if (typeof(this.value) == 'undefined') {
45340 var ar = Roo.decode(this.value);
45341 return ar instanceof Array ? ar : []; //?? valid?
45344 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
45349 expand : function ()
45351 Roo.form.ComboCheck.superclass.expand.call(this);
45352 this.valueBefore = this.value;
45357 collapse : function(){
45358 Roo.form.ComboCheck.superclass.collapse.call(this);
45359 var sl = this.view.getSelectedIndexes();
45360 var st = this.store;
45364 Roo.each(sl, function(i) {
45366 nv.push(r.get(this.valueField));
45368 this.setValue(Roo.encode(nv));
45369 if (this.value != this.valueBefore) {
45371 this.fireEvent('change', this, this.value, this.valueBefore);
45376 setValue : function(v){
45380 var vals = this.getValueArray();
45382 Roo.each(vals, function(k) {
45383 var r = this.findRecord(this.valueField, k);
45385 tv.push(r.data[this.displayField]);
45386 }else if(this.valueNotFoundText !== undefined){
45387 tv.push( this.valueNotFoundText );
45392 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
45393 this.hiddenField.value = v;
45397 });//<script type="text/javasscript">
45401 * @class Roo.DDView
45402 * A DnD enabled version of Roo.View.
45403 * @param {Element/String} container The Element in which to create the View.
45404 * @param {String} tpl The template string used to create the markup for each element of the View
45405 * @param {Object} config The configuration properties. These include all the config options of
45406 * {@link Roo.View} plus some specific to this class.<br>
45408 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
45409 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
45411 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
45412 .x-view-drag-insert-above {
45413 border-top:1px dotted #3366cc;
45415 .x-view-drag-insert-below {
45416 border-bottom:1px dotted #3366cc;
45422 Roo.DDView = function(container, tpl, config) {
45423 Roo.DDView.superclass.constructor.apply(this, arguments);
45424 this.getEl().setStyle("outline", "0px none");
45425 this.getEl().unselectable();
45426 if (this.dragGroup) {
45427 this.setDraggable(this.dragGroup.split(","));
45429 if (this.dropGroup) {
45430 this.setDroppable(this.dropGroup.split(","));
45432 if (this.deletable) {
45433 this.setDeletable();
45435 this.isDirtyFlag = false;
45441 Roo.extend(Roo.DDView, Roo.View, {
45442 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
45443 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
45444 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
45445 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
45449 reset: Roo.emptyFn,
45451 clearInvalid: Roo.form.Field.prototype.clearInvalid,
45453 validate: function() {
45457 destroy: function() {
45458 this.purgeListeners();
45459 this.getEl.removeAllListeners();
45460 this.getEl().remove();
45461 if (this.dragZone) {
45462 if (this.dragZone.destroy) {
45463 this.dragZone.destroy();
45466 if (this.dropZone) {
45467 if (this.dropZone.destroy) {
45468 this.dropZone.destroy();
45473 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
45474 getName: function() {
45478 /** Loads the View from a JSON string representing the Records to put into the Store. */
45479 setValue: function(v) {
45481 throw "DDView.setValue(). DDView must be constructed with a valid Store";
45484 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
45485 this.store.proxy = new Roo.data.MemoryProxy(data);
45489 /** @return {String} a parenthesised list of the ids of the Records in the View. */
45490 getValue: function() {
45492 this.store.each(function(rec) {
45493 result += rec.id + ',';
45495 return result.substr(0, result.length - 1) + ')';
45498 getIds: function() {
45499 var i = 0, result = new Array(this.store.getCount());
45500 this.store.each(function(rec) {
45501 result[i++] = rec.id;
45506 isDirty: function() {
45507 return this.isDirtyFlag;
45511 * Part of the Roo.dd.DropZone interface. If no target node is found, the
45512 * whole Element becomes the target, and this causes the drop gesture to append.
45514 getTargetFromEvent : function(e) {
45515 var target = e.getTarget();
45516 while ((target !== null) && (target.parentNode != this.el.dom)) {
45517 target = target.parentNode;
45520 target = this.el.dom.lastChild || this.el.dom;
45526 * Create the drag data which consists of an object which has the property "ddel" as
45527 * the drag proxy element.
45529 getDragData : function(e) {
45530 var target = this.findItemFromChild(e.getTarget());
45532 this.handleSelection(e);
45533 var selNodes = this.getSelectedNodes();
45536 copy: this.copy || (this.allowCopy && e.ctrlKey),
45540 var selectedIndices = this.getSelectedIndexes();
45541 for (var i = 0; i < selectedIndices.length; i++) {
45542 dragData.records.push(this.store.getAt(selectedIndices[i]));
45544 if (selNodes.length == 1) {
45545 dragData.ddel = target.cloneNode(true); // the div element
45547 var div = document.createElement('div'); // create the multi element drag "ghost"
45548 div.className = 'multi-proxy';
45549 for (var i = 0, len = selNodes.length; i < len; i++) {
45550 div.appendChild(selNodes[i].cloneNode(true));
45552 dragData.ddel = div;
45554 //console.log(dragData)
45555 //console.log(dragData.ddel.innerHTML)
45558 //console.log('nodragData')
45562 /** Specify to which ddGroup items in this DDView may be dragged. */
45563 setDraggable: function(ddGroup) {
45564 if (ddGroup instanceof Array) {
45565 Roo.each(ddGroup, this.setDraggable, this);
45568 if (this.dragZone) {
45569 this.dragZone.addToGroup(ddGroup);
45571 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
45572 containerScroll: true,
45576 // Draggability implies selection. DragZone's mousedown selects the element.
45577 if (!this.multiSelect) { this.singleSelect = true; }
45579 // Wire the DragZone's handlers up to methods in *this*
45580 this.dragZone.getDragData = this.getDragData.createDelegate(this);
45584 /** Specify from which ddGroup this DDView accepts drops. */
45585 setDroppable: function(ddGroup) {
45586 if (ddGroup instanceof Array) {
45587 Roo.each(ddGroup, this.setDroppable, this);
45590 if (this.dropZone) {
45591 this.dropZone.addToGroup(ddGroup);
45593 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
45594 containerScroll: true,
45598 // Wire the DropZone's handlers up to methods in *this*
45599 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
45600 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
45601 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
45602 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
45603 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
45607 /** Decide whether to drop above or below a View node. */
45608 getDropPoint : function(e, n, dd){
45609 if (n == this.el.dom) { return "above"; }
45610 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
45611 var c = t + (b - t) / 2;
45612 var y = Roo.lib.Event.getPageY(e);
45620 onNodeEnter : function(n, dd, e, data){
45624 onNodeOver : function(n, dd, e, data){
45625 var pt = this.getDropPoint(e, n, dd);
45626 // set the insert point style on the target node
45627 var dragElClass = this.dropNotAllowed;
45630 if (pt == "above"){
45631 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
45632 targetElClass = "x-view-drag-insert-above";
45634 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
45635 targetElClass = "x-view-drag-insert-below";
45637 if (this.lastInsertClass != targetElClass){
45638 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
45639 this.lastInsertClass = targetElClass;
45642 return dragElClass;
45645 onNodeOut : function(n, dd, e, data){
45646 this.removeDropIndicators(n);
45649 onNodeDrop : function(n, dd, e, data){
45650 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
45653 var pt = this.getDropPoint(e, n, dd);
45654 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
45655 if (pt == "below") { insertAt++; }
45656 for (var i = 0; i < data.records.length; i++) {
45657 var r = data.records[i];
45658 var dup = this.store.getById(r.id);
45659 if (dup && (dd != this.dragZone)) {
45660 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
45663 this.store.insert(insertAt++, r.copy());
45665 data.source.isDirtyFlag = true;
45667 this.store.insert(insertAt++, r);
45669 this.isDirtyFlag = true;
45672 this.dragZone.cachedTarget = null;
45676 removeDropIndicators : function(n){
45678 Roo.fly(n).removeClass([
45679 "x-view-drag-insert-above",
45680 "x-view-drag-insert-below"]);
45681 this.lastInsertClass = "_noclass";
45686 * Utility method. Add a delete option to the DDView's context menu.
45687 * @param {String} imageUrl The URL of the "delete" icon image.
45689 setDeletable: function(imageUrl) {
45690 if (!this.singleSelect && !this.multiSelect) {
45691 this.singleSelect = true;
45693 var c = this.getContextMenu();
45694 this.contextMenu.on("itemclick", function(item) {
45697 this.remove(this.getSelectedIndexes());
45701 this.contextMenu.add({
45708 /** Return the context menu for this DDView. */
45709 getContextMenu: function() {
45710 if (!this.contextMenu) {
45711 // Create the View's context menu
45712 this.contextMenu = new Roo.menu.Menu({
45713 id: this.id + "-contextmenu"
45715 this.el.on("contextmenu", this.showContextMenu, this);
45717 return this.contextMenu;
45720 disableContextMenu: function() {
45721 if (this.contextMenu) {
45722 this.el.un("contextmenu", this.showContextMenu, this);
45726 showContextMenu: function(e, item) {
45727 item = this.findItemFromChild(e.getTarget());
45730 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
45731 this.contextMenu.showAt(e.getXY());
45736 * Remove {@link Roo.data.Record}s at the specified indices.
45737 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
45739 remove: function(selectedIndices) {
45740 selectedIndices = [].concat(selectedIndices);
45741 for (var i = 0; i < selectedIndices.length; i++) {
45742 var rec = this.store.getAt(selectedIndices[i]);
45743 this.store.remove(rec);
45748 * Double click fires the event, but also, if this is draggable, and there is only one other
45749 * related DropZone, it transfers the selected node.
45751 onDblClick : function(e){
45752 var item = this.findItemFromChild(e.getTarget());
45754 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
45757 if (this.dragGroup) {
45758 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
45759 while (targets.indexOf(this.dropZone) > -1) {
45760 targets.remove(this.dropZone);
45762 if (targets.length == 1) {
45763 this.dragZone.cachedTarget = null;
45764 var el = Roo.get(targets[0].getEl());
45765 var box = el.getBox(true);
45766 targets[0].onNodeDrop(el.dom, {
45768 xy: [box.x, box.y + box.height - 1]
45769 }, null, this.getDragData(e));
45775 handleSelection: function(e) {
45776 this.dragZone.cachedTarget = null;
45777 var item = this.findItemFromChild(e.getTarget());
45779 this.clearSelections(true);
45782 if (item && (this.multiSelect || this.singleSelect)){
45783 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
45784 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
45785 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
45786 this.unselect(item);
45788 this.select(item, this.multiSelect && e.ctrlKey);
45789 this.lastSelection = item;
45794 onItemClick : function(item, index, e){
45795 if(this.fireEvent("beforeclick", this, index, item, e) === false){
45801 unselect : function(nodeInfo, suppressEvent){
45802 var node = this.getNode(nodeInfo);
45803 if(node && this.isSelected(node)){
45804 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
45805 Roo.fly(node).removeClass(this.selectedClass);
45806 this.selections.remove(node);
45807 if(!suppressEvent){
45808 this.fireEvent("selectionchange", this, this.selections);
45816 * Ext JS Library 1.1.1
45817 * Copyright(c) 2006-2007, Ext JS, LLC.
45819 * Originally Released Under LGPL - original licence link has changed is not relivant.
45822 * <script type="text/javascript">
45826 * @class Roo.LayoutManager
45827 * @extends Roo.util.Observable
45828 * Base class for layout managers.
45830 Roo.LayoutManager = function(container, config){
45831 Roo.LayoutManager.superclass.constructor.call(this);
45832 this.el = Roo.get(container);
45833 // ie scrollbar fix
45834 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
45835 document.body.scroll = "no";
45836 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
45837 this.el.position('relative');
45839 this.id = this.el.id;
45840 this.el.addClass("x-layout-container");
45841 /** false to disable window resize monitoring @type Boolean */
45842 this.monitorWindowResize = true;
45847 * Fires when a layout is performed.
45848 * @param {Roo.LayoutManager} this
45852 * @event regionresized
45853 * Fires when the user resizes a region.
45854 * @param {Roo.LayoutRegion} region The resized region
45855 * @param {Number} newSize The new size (width for east/west, height for north/south)
45857 "regionresized" : true,
45859 * @event regioncollapsed
45860 * Fires when a region is collapsed.
45861 * @param {Roo.LayoutRegion} region The collapsed region
45863 "regioncollapsed" : true,
45865 * @event regionexpanded
45866 * Fires when a region is expanded.
45867 * @param {Roo.LayoutRegion} region The expanded region
45869 "regionexpanded" : true
45871 this.updating = false;
45872 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
45875 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
45877 * Returns true if this layout is currently being updated
45878 * @return {Boolean}
45880 isUpdating : function(){
45881 return this.updating;
45885 * Suspend the LayoutManager from doing auto-layouts while
45886 * making multiple add or remove calls
45888 beginUpdate : function(){
45889 this.updating = true;
45893 * Restore auto-layouts and optionally disable the manager from performing a layout
45894 * @param {Boolean} noLayout true to disable a layout update
45896 endUpdate : function(noLayout){
45897 this.updating = false;
45903 layout: function(){
45907 onRegionResized : function(region, newSize){
45908 this.fireEvent("regionresized", region, newSize);
45912 onRegionCollapsed : function(region){
45913 this.fireEvent("regioncollapsed", region);
45916 onRegionExpanded : function(region){
45917 this.fireEvent("regionexpanded", region);
45921 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
45922 * performs box-model adjustments.
45923 * @return {Object} The size as an object {width: (the width), height: (the height)}
45925 getViewSize : function(){
45927 if(this.el.dom != document.body){
45928 size = this.el.getSize();
45930 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
45932 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
45933 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
45938 * Returns the Element this layout is bound to.
45939 * @return {Roo.Element}
45941 getEl : function(){
45946 * Returns the specified region.
45947 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
45948 * @return {Roo.LayoutRegion}
45950 getRegion : function(target){
45951 return this.regions[target.toLowerCase()];
45954 onWindowResize : function(){
45955 if(this.monitorWindowResize){
45961 * Ext JS Library 1.1.1
45962 * Copyright(c) 2006-2007, Ext JS, LLC.
45964 * Originally Released Under LGPL - original licence link has changed is not relivant.
45967 * <script type="text/javascript">
45970 * @class Roo.BorderLayout
45971 * @extends Roo.LayoutManager
45972 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
45973 * please see: <br><br>
45974 * <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>
45975 * <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>
45978 var layout = new Roo.BorderLayout(document.body, {
46012 preferredTabWidth: 150
46017 var CP = Roo.ContentPanel;
46019 layout.beginUpdate();
46020 layout.add("north", new CP("north", "North"));
46021 layout.add("south", new CP("south", {title: "South", closable: true}));
46022 layout.add("west", new CP("west", {title: "West"}));
46023 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
46024 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
46025 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
46026 layout.getRegion("center").showPanel("center1");
46027 layout.endUpdate();
46030 <b>The container the layout is rendered into can be either the body element or any other element.
46031 If it is not the body element, the container needs to either be an absolute positioned element,
46032 or you will need to add "position:relative" to the css of the container. You will also need to specify
46033 the container size if it is not the body element.</b>
46036 * Create a new BorderLayout
46037 * @param {String/HTMLElement/Element} container The container this layout is bound to
46038 * @param {Object} config Configuration options
46040 Roo.BorderLayout = function(container, config){
46041 config = config || {};
46042 Roo.BorderLayout.superclass.constructor.call(this, container, config);
46043 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
46044 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
46045 var target = this.factory.validRegions[i];
46046 if(config[target]){
46047 this.addRegion(target, config[target]);
46052 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
46054 * Creates and adds a new region if it doesn't already exist.
46055 * @param {String} target The target region key (north, south, east, west or center).
46056 * @param {Object} config The regions config object
46057 * @return {BorderLayoutRegion} The new region
46059 addRegion : function(target, config){
46060 if(!this.regions[target]){
46061 var r = this.factory.create(target, this, config);
46062 this.bindRegion(target, r);
46064 return this.regions[target];
46068 bindRegion : function(name, r){
46069 this.regions[name] = r;
46070 r.on("visibilitychange", this.layout, this);
46071 r.on("paneladded", this.layout, this);
46072 r.on("panelremoved", this.layout, this);
46073 r.on("invalidated", this.layout, this);
46074 r.on("resized", this.onRegionResized, this);
46075 r.on("collapsed", this.onRegionCollapsed, this);
46076 r.on("expanded", this.onRegionExpanded, this);
46080 * Performs a layout update.
46082 layout : function(){
46083 if(this.updating) return;
46084 var size = this.getViewSize();
46085 var w = size.width;
46086 var h = size.height;
46091 //var x = 0, y = 0;
46093 var rs = this.regions;
46094 var north = rs["north"];
46095 var south = rs["south"];
46096 var west = rs["west"];
46097 var east = rs["east"];
46098 var center = rs["center"];
46099 //if(this.hideOnLayout){ // not supported anymore
46100 //c.el.setStyle("display", "none");
46102 if(north && north.isVisible()){
46103 var b = north.getBox();
46104 var m = north.getMargins();
46105 b.width = w - (m.left+m.right);
46108 centerY = b.height + b.y + m.bottom;
46109 centerH -= centerY;
46110 north.updateBox(this.safeBox(b));
46112 if(south && south.isVisible()){
46113 var b = south.getBox();
46114 var m = south.getMargins();
46115 b.width = w - (m.left+m.right);
46117 var totalHeight = (b.height + m.top + m.bottom);
46118 b.y = h - totalHeight + m.top;
46119 centerH -= totalHeight;
46120 south.updateBox(this.safeBox(b));
46122 if(west && west.isVisible()){
46123 var b = west.getBox();
46124 var m = west.getMargins();
46125 b.height = centerH - (m.top+m.bottom);
46127 b.y = centerY + m.top;
46128 var totalWidth = (b.width + m.left + m.right);
46129 centerX += totalWidth;
46130 centerW -= totalWidth;
46131 west.updateBox(this.safeBox(b));
46133 if(east && east.isVisible()){
46134 var b = east.getBox();
46135 var m = east.getMargins();
46136 b.height = centerH - (m.top+m.bottom);
46137 var totalWidth = (b.width + m.left + m.right);
46138 b.x = w - totalWidth + m.left;
46139 b.y = centerY + m.top;
46140 centerW -= totalWidth;
46141 east.updateBox(this.safeBox(b));
46144 var m = center.getMargins();
46146 x: centerX + m.left,
46147 y: centerY + m.top,
46148 width: centerW - (m.left+m.right),
46149 height: centerH - (m.top+m.bottom)
46151 //if(this.hideOnLayout){
46152 //center.el.setStyle("display", "block");
46154 center.updateBox(this.safeBox(centerBox));
46157 this.fireEvent("layout", this);
46161 safeBox : function(box){
46162 box.width = Math.max(0, box.width);
46163 box.height = Math.max(0, box.height);
46168 * Adds a ContentPanel (or subclass) to this layout.
46169 * @param {String} target The target region key (north, south, east, west or center).
46170 * @param {Roo.ContentPanel} panel The panel to add
46171 * @return {Roo.ContentPanel} The added panel
46173 add : function(target, panel){
46175 target = target.toLowerCase();
46176 return this.regions[target].add(panel);
46180 * Remove a ContentPanel (or subclass) to this layout.
46181 * @param {String} target The target region key (north, south, east, west or center).
46182 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
46183 * @return {Roo.ContentPanel} The removed panel
46185 remove : function(target, panel){
46186 target = target.toLowerCase();
46187 return this.regions[target].remove(panel);
46191 * Searches all regions for a panel with the specified id
46192 * @param {String} panelId
46193 * @return {Roo.ContentPanel} The panel or null if it wasn't found
46195 findPanel : function(panelId){
46196 var rs = this.regions;
46197 for(var target in rs){
46198 if(typeof rs[target] != "function"){
46199 var p = rs[target].getPanel(panelId);
46209 * Searches all regions for a panel with the specified id and activates (shows) it.
46210 * @param {String/ContentPanel} panelId The panels id or the panel itself
46211 * @return {Roo.ContentPanel} The shown panel or null
46213 showPanel : function(panelId) {
46214 var rs = this.regions;
46215 for(var target in rs){
46216 var r = rs[target];
46217 if(typeof r != "function"){
46218 if(r.hasPanel(panelId)){
46219 return r.showPanel(panelId);
46227 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
46228 * @param {Roo.state.Provider} provider (optional) An alternate state provider
46230 restoreState : function(provider){
46232 provider = Roo.state.Manager;
46234 var sm = new Roo.LayoutStateManager();
46235 sm.init(this, provider);
46239 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
46240 * object should contain properties for each region to add ContentPanels to, and each property's value should be
46241 * a valid ContentPanel config object. Example:
46243 // Create the main layout
46244 var layout = new Roo.BorderLayout('main-ct', {
46255 // Create and add multiple ContentPanels at once via configs
46258 id: 'source-files',
46260 title:'Ext Source Files',
46273 * @param {Object} regions An object containing ContentPanel configs by region name
46275 batchAdd : function(regions){
46276 this.beginUpdate();
46277 for(var rname in regions){
46278 var lr = this.regions[rname];
46280 this.addTypedPanels(lr, regions[rname]);
46287 addTypedPanels : function(lr, ps){
46288 if(typeof ps == 'string'){
46289 lr.add(new Roo.ContentPanel(ps));
46291 else if(ps instanceof Array){
46292 for(var i =0, len = ps.length; i < len; i++){
46293 this.addTypedPanels(lr, ps[i]);
46296 else if(!ps.events){ // raw config?
46298 delete ps.el; // prevent conflict
46299 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
46301 else { // panel object assumed!
46306 * Adds a xtype elements to the layout.
46310 xtype : 'ContentPanel',
46317 xtype : 'NestedLayoutPanel',
46323 items : [ ... list of content panels or nested layout panels.. ]
46327 * @param {Object} cfg Xtype definition of item to add.
46329 addxtype : function(cfg)
46331 // basically accepts a pannel...
46332 // can accept a layout region..!?!?
46333 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
46335 if (!cfg.xtype.match(/Panel$/)) {
46340 if (typeof(cfg.region) == 'undefined') {
46341 Roo.log("Failed to add Panel, region was not set");
46345 var region = cfg.region;
46351 xitems = cfg.items;
46358 case 'ContentPanel': // ContentPanel (el, cfg)
46359 case 'ScrollPanel': // ContentPanel (el, cfg)
46360 if(cfg.autoCreate) {
46361 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
46363 var el = this.el.createChild();
46364 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
46367 this.add(region, ret);
46371 case 'TreePanel': // our new panel!
46372 cfg.el = this.el.createChild();
46373 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
46374 this.add(region, ret);
46377 case 'NestedLayoutPanel':
46378 // create a new Layout (which is a Border Layout...
46379 var el = this.el.createChild();
46380 var clayout = cfg.layout;
46382 clayout.items = clayout.items || [];
46383 // replace this exitems with the clayout ones..
46384 xitems = clayout.items;
46387 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
46388 cfg.background = false;
46390 var layout = new Roo.BorderLayout(el, clayout);
46392 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
46393 //console.log('adding nested layout panel ' + cfg.toSource());
46394 this.add(region, ret);
46395 nb = {}; /// find first...
46400 // needs grid and region
46402 //var el = this.getRegion(region).el.createChild();
46403 var el = this.el.createChild();
46404 // create the grid first...
46406 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
46408 if (region == 'center' && this.active ) {
46409 cfg.background = false;
46411 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
46413 this.add(region, ret);
46414 if (cfg.background) {
46415 ret.on('activate', function(gp) {
46416 if (!gp.grid.rendered) {
46429 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
46431 // GridPanel (grid, cfg)
46434 this.beginUpdate();
46438 Roo.each(xitems, function(i) {
46439 region = nb && i.region ? i.region : false;
46441 var add = ret.addxtype(i);
46444 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
46445 if (!i.background) {
46446 abn[region] = nb[region] ;
46453 // make the last non-background panel active..
46454 //if (nb) { Roo.log(abn); }
46457 for(var r in abn) {
46458 region = this.getRegion(r);
46460 // tried using nb[r], but it does not work..
46462 region.showPanel(abn[r]);
46473 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
46474 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
46475 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
46476 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
46479 var CP = Roo.ContentPanel;
46481 var layout = Roo.BorderLayout.create({
46485 panels: [new CP("north", "North")]
46494 panels: [new CP("west", {title: "West"})]
46503 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
46512 panels: [new CP("south", {title: "South", closable: true})]
46519 preferredTabWidth: 150,
46521 new CP("center1", {title: "Close Me", closable: true}),
46522 new CP("center2", {title: "Center Panel", closable: false})
46527 layout.getRegion("center").showPanel("center1");
46532 Roo.BorderLayout.create = function(config, targetEl){
46533 var layout = new Roo.BorderLayout(targetEl || document.body, config);
46534 layout.beginUpdate();
46535 var regions = Roo.BorderLayout.RegionFactory.validRegions;
46536 for(var j = 0, jlen = regions.length; j < jlen; j++){
46537 var lr = regions[j];
46538 if(layout.regions[lr] && config[lr].panels){
46539 var r = layout.regions[lr];
46540 var ps = config[lr].panels;
46541 layout.addTypedPanels(r, ps);
46544 layout.endUpdate();
46549 Roo.BorderLayout.RegionFactory = {
46551 validRegions : ["north","south","east","west","center"],
46554 create : function(target, mgr, config){
46555 target = target.toLowerCase();
46556 if(config.lightweight || config.basic){
46557 return new Roo.BasicLayoutRegion(mgr, config, target);
46561 return new Roo.NorthLayoutRegion(mgr, config);
46563 return new Roo.SouthLayoutRegion(mgr, config);
46565 return new Roo.EastLayoutRegion(mgr, config);
46567 return new Roo.WestLayoutRegion(mgr, config);
46569 return new Roo.CenterLayoutRegion(mgr, config);
46571 throw 'Layout region "'+target+'" not supported.';
46575 * Ext JS Library 1.1.1
46576 * Copyright(c) 2006-2007, Ext JS, LLC.
46578 * Originally Released Under LGPL - original licence link has changed is not relivant.
46581 * <script type="text/javascript">
46585 * @class Roo.BasicLayoutRegion
46586 * @extends Roo.util.Observable
46587 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
46588 * and does not have a titlebar, tabs or any other features. All it does is size and position
46589 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
46591 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
46593 this.position = pos;
46596 * @scope Roo.BasicLayoutRegion
46600 * @event beforeremove
46601 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
46602 * @param {Roo.LayoutRegion} this
46603 * @param {Roo.ContentPanel} panel The panel
46604 * @param {Object} e The cancel event object
46606 "beforeremove" : true,
46608 * @event invalidated
46609 * Fires when the layout for this region is changed.
46610 * @param {Roo.LayoutRegion} this
46612 "invalidated" : true,
46614 * @event visibilitychange
46615 * Fires when this region is shown or hidden
46616 * @param {Roo.LayoutRegion} this
46617 * @param {Boolean} visibility true or false
46619 "visibilitychange" : true,
46621 * @event paneladded
46622 * Fires when a panel is added.
46623 * @param {Roo.LayoutRegion} this
46624 * @param {Roo.ContentPanel} panel The panel
46626 "paneladded" : true,
46628 * @event panelremoved
46629 * Fires when a panel is removed.
46630 * @param {Roo.LayoutRegion} this
46631 * @param {Roo.ContentPanel} panel The panel
46633 "panelremoved" : true,
46636 * Fires when this region is collapsed.
46637 * @param {Roo.LayoutRegion} this
46639 "collapsed" : true,
46642 * Fires when this region is expanded.
46643 * @param {Roo.LayoutRegion} this
46648 * Fires when this region is slid into view.
46649 * @param {Roo.LayoutRegion} this
46651 "slideshow" : true,
46654 * Fires when this region slides out of view.
46655 * @param {Roo.LayoutRegion} this
46657 "slidehide" : true,
46659 * @event panelactivated
46660 * Fires when a panel is activated.
46661 * @param {Roo.LayoutRegion} this
46662 * @param {Roo.ContentPanel} panel The activated panel
46664 "panelactivated" : true,
46667 * Fires when the user resizes this region.
46668 * @param {Roo.LayoutRegion} this
46669 * @param {Number} newSize The new size (width for east/west, height for north/south)
46673 /** A collection of panels in this region. @type Roo.util.MixedCollection */
46674 this.panels = new Roo.util.MixedCollection();
46675 this.panels.getKey = this.getPanelId.createDelegate(this);
46677 this.activePanel = null;
46678 // ensure listeners are added...
46680 if (config.listeners || config.events) {
46681 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
46682 listeners : config.listeners || {},
46683 events : config.events || {}
46687 if(skipConfig !== true){
46688 this.applyConfig(config);
46692 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
46693 getPanelId : function(p){
46697 applyConfig : function(config){
46698 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
46699 this.config = config;
46704 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
46705 * the width, for horizontal (north, south) the height.
46706 * @param {Number} newSize The new width or height
46708 resizeTo : function(newSize){
46709 var el = this.el ? this.el :
46710 (this.activePanel ? this.activePanel.getEl() : null);
46712 switch(this.position){
46715 el.setWidth(newSize);
46716 this.fireEvent("resized", this, newSize);
46720 el.setHeight(newSize);
46721 this.fireEvent("resized", this, newSize);
46727 getBox : function(){
46728 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
46731 getMargins : function(){
46732 return this.margins;
46735 updateBox : function(box){
46737 var el = this.activePanel.getEl();
46738 el.dom.style.left = box.x + "px";
46739 el.dom.style.top = box.y + "px";
46740 this.activePanel.setSize(box.width, box.height);
46744 * Returns the container element for this region.
46745 * @return {Roo.Element}
46747 getEl : function(){
46748 return this.activePanel;
46752 * Returns true if this region is currently visible.
46753 * @return {Boolean}
46755 isVisible : function(){
46756 return this.activePanel ? true : false;
46759 setActivePanel : function(panel){
46760 panel = this.getPanel(panel);
46761 if(this.activePanel && this.activePanel != panel){
46762 this.activePanel.setActiveState(false);
46763 this.activePanel.getEl().setLeftTop(-10000,-10000);
46765 this.activePanel = panel;
46766 panel.setActiveState(true);
46768 panel.setSize(this.box.width, this.box.height);
46770 this.fireEvent("panelactivated", this, panel);
46771 this.fireEvent("invalidated");
46775 * Show the specified panel.
46776 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
46777 * @return {Roo.ContentPanel} The shown panel or null
46779 showPanel : function(panel){
46780 if(panel = this.getPanel(panel)){
46781 this.setActivePanel(panel);
46787 * Get the active panel for this region.
46788 * @return {Roo.ContentPanel} The active panel or null
46790 getActivePanel : function(){
46791 return this.activePanel;
46795 * Add the passed ContentPanel(s)
46796 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
46797 * @return {Roo.ContentPanel} The panel added (if only one was added)
46799 add : function(panel){
46800 if(arguments.length > 1){
46801 for(var i = 0, len = arguments.length; i < len; i++) {
46802 this.add(arguments[i]);
46806 if(this.hasPanel(panel)){
46807 this.showPanel(panel);
46810 var el = panel.getEl();
46811 if(el.dom.parentNode != this.mgr.el.dom){
46812 this.mgr.el.dom.appendChild(el.dom);
46814 if(panel.setRegion){
46815 panel.setRegion(this);
46817 this.panels.add(panel);
46818 el.setStyle("position", "absolute");
46819 if(!panel.background){
46820 this.setActivePanel(panel);
46821 if(this.config.initialSize && this.panels.getCount()==1){
46822 this.resizeTo(this.config.initialSize);
46825 this.fireEvent("paneladded", this, panel);
46830 * Returns true if the panel is in this region.
46831 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46832 * @return {Boolean}
46834 hasPanel : function(panel){
46835 if(typeof panel == "object"){ // must be panel obj
46836 panel = panel.getId();
46838 return this.getPanel(panel) ? true : false;
46842 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
46843 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46844 * @param {Boolean} preservePanel Overrides the config preservePanel option
46845 * @return {Roo.ContentPanel} The panel that was removed
46847 remove : function(panel, preservePanel){
46848 panel = this.getPanel(panel);
46853 this.fireEvent("beforeremove", this, panel, e);
46854 if(e.cancel === true){
46857 var panelId = panel.getId();
46858 this.panels.removeKey(panelId);
46863 * Returns the panel specified or null if it's not in this region.
46864 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46865 * @return {Roo.ContentPanel}
46867 getPanel : function(id){
46868 if(typeof id == "object"){ // must be panel obj
46871 return this.panels.get(id);
46875 * Returns this regions position (north/south/east/west/center).
46878 getPosition: function(){
46879 return this.position;
46883 * Ext JS Library 1.1.1
46884 * Copyright(c) 2006-2007, Ext JS, LLC.
46886 * Originally Released Under LGPL - original licence link has changed is not relivant.
46889 * <script type="text/javascript">
46893 * @class Roo.LayoutRegion
46894 * @extends Roo.BasicLayoutRegion
46895 * This class represents a region in a layout manager.
46896 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
46897 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
46898 * @cfg {Boolean} floatable False to disable floating (defaults to true)
46899 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
46900 * @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})
46901 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
46902 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
46903 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
46904 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
46905 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
46906 * @cfg {String} title The title for the region (overrides panel titles)
46907 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
46908 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
46909 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
46910 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
46911 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
46912 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
46913 * the space available, similar to FireFox 1.5 tabs (defaults to false)
46914 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
46915 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
46916 * @cfg {Boolean} showPin True to show a pin button
46917 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
46918 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
46919 * @cfg {Boolean} disableTabTips True to disable tab tooltips
46920 * @cfg {Number} width For East/West panels
46921 * @cfg {Number} height For North/South panels
46922 * @cfg {Boolean} split To show the splitter
46923 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
46925 Roo.LayoutRegion = function(mgr, config, pos){
46926 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
46927 var dh = Roo.DomHelper;
46928 /** This region's container element
46929 * @type Roo.Element */
46930 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
46931 /** This region's title element
46932 * @type Roo.Element */
46934 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
46935 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
46936 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
46938 this.titleEl.enableDisplayMode();
46939 /** This region's title text element
46940 * @type HTMLElement */
46941 this.titleTextEl = this.titleEl.dom.firstChild;
46942 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
46943 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
46944 this.closeBtn.enableDisplayMode();
46945 this.closeBtn.on("click", this.closeClicked, this);
46946 this.closeBtn.hide();
46948 this.createBody(config);
46949 this.visible = true;
46950 this.collapsed = false;
46952 if(config.hideWhenEmpty){
46954 this.on("paneladded", this.validateVisibility, this);
46955 this.on("panelremoved", this.validateVisibility, this);
46957 this.applyConfig(config);
46960 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
46962 createBody : function(){
46963 /** This region's body element
46964 * @type Roo.Element */
46965 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
46968 applyConfig : function(c){
46969 if(c.collapsible && this.position != "center" && !this.collapsedEl){
46970 var dh = Roo.DomHelper;
46971 if(c.titlebar !== false){
46972 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
46973 this.collapseBtn.on("click", this.collapse, this);
46974 this.collapseBtn.enableDisplayMode();
46976 if(c.showPin === true || this.showPin){
46977 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
46978 this.stickBtn.enableDisplayMode();
46979 this.stickBtn.on("click", this.expand, this);
46980 this.stickBtn.hide();
46983 /** This region's collapsed element
46984 * @type Roo.Element */
46985 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
46986 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
46988 if(c.floatable !== false){
46989 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
46990 this.collapsedEl.on("click", this.collapseClick, this);
46993 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
46994 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
46995 id: "message", unselectable: "on", style:{"float":"left"}});
46996 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
46998 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
46999 this.expandBtn.on("click", this.expand, this);
47001 if(this.collapseBtn){
47002 this.collapseBtn.setVisible(c.collapsible == true);
47004 this.cmargins = c.cmargins || this.cmargins ||
47005 (this.position == "west" || this.position == "east" ?
47006 {top: 0, left: 2, right:2, bottom: 0} :
47007 {top: 2, left: 0, right:0, bottom: 2});
47008 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
47009 this.bottomTabs = c.tabPosition != "top";
47010 this.autoScroll = c.autoScroll || false;
47011 if(this.autoScroll){
47012 this.bodyEl.setStyle("overflow", "auto");
47014 this.bodyEl.setStyle("overflow", "hidden");
47016 //if(c.titlebar !== false){
47017 if((!c.titlebar && !c.title) || c.titlebar === false){
47018 this.titleEl.hide();
47020 this.titleEl.show();
47022 this.titleTextEl.innerHTML = c.title;
47026 this.duration = c.duration || .30;
47027 this.slideDuration = c.slideDuration || .45;
47030 this.collapse(true);
47037 * Returns true if this region is currently visible.
47038 * @return {Boolean}
47040 isVisible : function(){
47041 return this.visible;
47045 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
47046 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
47048 setCollapsedTitle : function(title){
47049 title = title || " ";
47050 if(this.collapsedTitleTextEl){
47051 this.collapsedTitleTextEl.innerHTML = title;
47055 getBox : function(){
47057 if(!this.collapsed){
47058 b = this.el.getBox(false, true);
47060 b = this.collapsedEl.getBox(false, true);
47065 getMargins : function(){
47066 return this.collapsed ? this.cmargins : this.margins;
47069 highlight : function(){
47070 this.el.addClass("x-layout-panel-dragover");
47073 unhighlight : function(){
47074 this.el.removeClass("x-layout-panel-dragover");
47077 updateBox : function(box){
47079 if(!this.collapsed){
47080 this.el.dom.style.left = box.x + "px";
47081 this.el.dom.style.top = box.y + "px";
47082 this.updateBody(box.width, box.height);
47084 this.collapsedEl.dom.style.left = box.x + "px";
47085 this.collapsedEl.dom.style.top = box.y + "px";
47086 this.collapsedEl.setSize(box.width, box.height);
47089 this.tabs.autoSizeTabs();
47093 updateBody : function(w, h){
47095 this.el.setWidth(w);
47096 w -= this.el.getBorderWidth("rl");
47097 if(this.config.adjustments){
47098 w += this.config.adjustments[0];
47102 this.el.setHeight(h);
47103 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
47104 h -= this.el.getBorderWidth("tb");
47105 if(this.config.adjustments){
47106 h += this.config.adjustments[1];
47108 this.bodyEl.setHeight(h);
47110 h = this.tabs.syncHeight(h);
47113 if(this.panelSize){
47114 w = w !== null ? w : this.panelSize.width;
47115 h = h !== null ? h : this.panelSize.height;
47117 if(this.activePanel){
47118 var el = this.activePanel.getEl();
47119 w = w !== null ? w : el.getWidth();
47120 h = h !== null ? h : el.getHeight();
47121 this.panelSize = {width: w, height: h};
47122 this.activePanel.setSize(w, h);
47124 if(Roo.isIE && this.tabs){
47125 this.tabs.el.repaint();
47130 * Returns the container element for this region.
47131 * @return {Roo.Element}
47133 getEl : function(){
47138 * Hides this region.
47141 if(!this.collapsed){
47142 this.el.dom.style.left = "-2000px";
47145 this.collapsedEl.dom.style.left = "-2000px";
47146 this.collapsedEl.hide();
47148 this.visible = false;
47149 this.fireEvent("visibilitychange", this, false);
47153 * Shows this region if it was previously hidden.
47156 if(!this.collapsed){
47159 this.collapsedEl.show();
47161 this.visible = true;
47162 this.fireEvent("visibilitychange", this, true);
47165 closeClicked : function(){
47166 if(this.activePanel){
47167 this.remove(this.activePanel);
47171 collapseClick : function(e){
47173 e.stopPropagation();
47176 e.stopPropagation();
47182 * Collapses this region.
47183 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
47185 collapse : function(skipAnim){
47186 if(this.collapsed) return;
47187 this.collapsed = true;
47189 this.split.el.hide();
47191 if(this.config.animate && skipAnim !== true){
47192 this.fireEvent("invalidated", this);
47193 this.animateCollapse();
47195 this.el.setLocation(-20000,-20000);
47197 this.collapsedEl.show();
47198 this.fireEvent("collapsed", this);
47199 this.fireEvent("invalidated", this);
47203 animateCollapse : function(){
47208 * Expands this region if it was previously collapsed.
47209 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
47210 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
47212 expand : function(e, skipAnim){
47213 if(e) e.stopPropagation();
47214 if(!this.collapsed || this.el.hasActiveFx()) return;
47216 this.afterSlideIn();
47219 this.collapsed = false;
47220 if(this.config.animate && skipAnim !== true){
47221 this.animateExpand();
47225 this.split.el.show();
47227 this.collapsedEl.setLocation(-2000,-2000);
47228 this.collapsedEl.hide();
47229 this.fireEvent("invalidated", this);
47230 this.fireEvent("expanded", this);
47234 animateExpand : function(){
47238 initTabs : function()
47240 this.bodyEl.setStyle("overflow", "hidden");
47241 var ts = new Roo.TabPanel(
47244 tabPosition: this.bottomTabs ? 'bottom' : 'top',
47245 disableTooltips: this.config.disableTabTips,
47246 toolbar : this.config.toolbar
47249 if(this.config.hideTabs){
47250 ts.stripWrap.setDisplayed(false);
47253 ts.resizeTabs = this.config.resizeTabs === true;
47254 ts.minTabWidth = this.config.minTabWidth || 40;
47255 ts.maxTabWidth = this.config.maxTabWidth || 250;
47256 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
47257 ts.monitorResize = false;
47258 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
47259 ts.bodyEl.addClass('x-layout-tabs-body');
47260 this.panels.each(this.initPanelAsTab, this);
47263 initPanelAsTab : function(panel){
47264 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
47265 this.config.closeOnTab && panel.isClosable());
47266 if(panel.tabTip !== undefined){
47267 ti.setTooltip(panel.tabTip);
47269 ti.on("activate", function(){
47270 this.setActivePanel(panel);
47272 if(this.config.closeOnTab){
47273 ti.on("beforeclose", function(t, e){
47275 this.remove(panel);
47281 updatePanelTitle : function(panel, title){
47282 if(this.activePanel == panel){
47283 this.updateTitle(title);
47286 var ti = this.tabs.getTab(panel.getEl().id);
47288 if(panel.tabTip !== undefined){
47289 ti.setTooltip(panel.tabTip);
47294 updateTitle : function(title){
47295 if(this.titleTextEl && !this.config.title){
47296 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
47300 setActivePanel : function(panel){
47301 panel = this.getPanel(panel);
47302 if(this.activePanel && this.activePanel != panel){
47303 this.activePanel.setActiveState(false);
47305 this.activePanel = panel;
47306 panel.setActiveState(true);
47307 if(this.panelSize){
47308 panel.setSize(this.panelSize.width, this.panelSize.height);
47311 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
47313 this.updateTitle(panel.getTitle());
47315 this.fireEvent("invalidated", this);
47317 this.fireEvent("panelactivated", this, panel);
47321 * Shows the specified panel.
47322 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
47323 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
47325 showPanel : function(panel){
47326 if(panel = this.getPanel(panel)){
47328 var tab = this.tabs.getTab(panel.getEl().id);
47329 if(tab.isHidden()){
47330 this.tabs.unhideTab(tab.id);
47334 this.setActivePanel(panel);
47341 * Get the active panel for this region.
47342 * @return {Roo.ContentPanel} The active panel or null
47344 getActivePanel : function(){
47345 return this.activePanel;
47348 validateVisibility : function(){
47349 if(this.panels.getCount() < 1){
47350 this.updateTitle(" ");
47351 this.closeBtn.hide();
47354 if(!this.isVisible()){
47361 * Adds the passed ContentPanel(s) to this region.
47362 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
47363 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
47365 add : function(panel){
47366 if(arguments.length > 1){
47367 for(var i = 0, len = arguments.length; i < len; i++) {
47368 this.add(arguments[i]);
47372 if(this.hasPanel(panel)){
47373 this.showPanel(panel);
47376 panel.setRegion(this);
47377 this.panels.add(panel);
47378 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
47379 this.bodyEl.dom.appendChild(panel.getEl().dom);
47380 if(panel.background !== true){
47381 this.setActivePanel(panel);
47383 this.fireEvent("paneladded", this, panel);
47389 this.initPanelAsTab(panel);
47391 if(panel.background !== true){
47392 this.tabs.activate(panel.getEl().id);
47394 this.fireEvent("paneladded", this, panel);
47399 * Hides the tab for the specified panel.
47400 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47402 hidePanel : function(panel){
47403 if(this.tabs && (panel = this.getPanel(panel))){
47404 this.tabs.hideTab(panel.getEl().id);
47409 * Unhides the tab for a previously hidden panel.
47410 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47412 unhidePanel : function(panel){
47413 if(this.tabs && (panel = this.getPanel(panel))){
47414 this.tabs.unhideTab(panel.getEl().id);
47418 clearPanels : function(){
47419 while(this.panels.getCount() > 0){
47420 this.remove(this.panels.first());
47425 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
47426 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47427 * @param {Boolean} preservePanel Overrides the config preservePanel option
47428 * @return {Roo.ContentPanel} The panel that was removed
47430 remove : function(panel, preservePanel){
47431 panel = this.getPanel(panel);
47436 this.fireEvent("beforeremove", this, panel, e);
47437 if(e.cancel === true){
47440 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
47441 var panelId = panel.getId();
47442 this.panels.removeKey(panelId);
47444 document.body.appendChild(panel.getEl().dom);
47447 this.tabs.removeTab(panel.getEl().id);
47448 }else if (!preservePanel){
47449 this.bodyEl.dom.removeChild(panel.getEl().dom);
47451 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
47452 var p = this.panels.first();
47453 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
47454 tempEl.appendChild(p.getEl().dom);
47455 this.bodyEl.update("");
47456 this.bodyEl.dom.appendChild(p.getEl().dom);
47458 this.updateTitle(p.getTitle());
47460 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
47461 this.setActivePanel(p);
47463 panel.setRegion(null);
47464 if(this.activePanel == panel){
47465 this.activePanel = null;
47467 if(this.config.autoDestroy !== false && preservePanel !== true){
47468 try{panel.destroy();}catch(e){}
47470 this.fireEvent("panelremoved", this, panel);
47475 * Returns the TabPanel component used by this region
47476 * @return {Roo.TabPanel}
47478 getTabs : function(){
47482 createTool : function(parentEl, className){
47483 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
47484 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
47485 btn.addClassOnOver("x-layout-tools-button-over");
47490 * Ext JS Library 1.1.1
47491 * Copyright(c) 2006-2007, Ext JS, LLC.
47493 * Originally Released Under LGPL - original licence link has changed is not relivant.
47496 * <script type="text/javascript">
47502 * @class Roo.SplitLayoutRegion
47503 * @extends Roo.LayoutRegion
47504 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
47506 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
47507 this.cursor = cursor;
47508 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
47511 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
47512 splitTip : "Drag to resize.",
47513 collapsibleSplitTip : "Drag to resize. Double click to hide.",
47514 useSplitTips : false,
47516 applyConfig : function(config){
47517 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
47520 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
47521 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
47522 /** The SplitBar for this region
47523 * @type Roo.SplitBar */
47524 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
47525 this.split.on("moved", this.onSplitMove, this);
47526 this.split.useShim = config.useShim === true;
47527 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
47528 if(this.useSplitTips){
47529 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
47531 if(config.collapsible){
47532 this.split.el.on("dblclick", this.collapse, this);
47535 if(typeof config.minSize != "undefined"){
47536 this.split.minSize = config.minSize;
47538 if(typeof config.maxSize != "undefined"){
47539 this.split.maxSize = config.maxSize;
47541 if(config.hideWhenEmpty || config.hidden || config.collapsed){
47542 this.hideSplitter();
47547 getHMaxSize : function(){
47548 var cmax = this.config.maxSize || 10000;
47549 var center = this.mgr.getRegion("center");
47550 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
47553 getVMaxSize : function(){
47554 var cmax = this.config.maxSize || 10000;
47555 var center = this.mgr.getRegion("center");
47556 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
47559 onSplitMove : function(split, newSize){
47560 this.fireEvent("resized", this, newSize);
47564 * Returns the {@link Roo.SplitBar} for this region.
47565 * @return {Roo.SplitBar}
47567 getSplitBar : function(){
47572 this.hideSplitter();
47573 Roo.SplitLayoutRegion.superclass.hide.call(this);
47576 hideSplitter : function(){
47578 this.split.el.setLocation(-2000,-2000);
47579 this.split.el.hide();
47585 this.split.el.show();
47587 Roo.SplitLayoutRegion.superclass.show.call(this);
47590 beforeSlide: function(){
47591 if(Roo.isGecko){// firefox overflow auto bug workaround
47592 this.bodyEl.clip();
47593 if(this.tabs) this.tabs.bodyEl.clip();
47594 if(this.activePanel){
47595 this.activePanel.getEl().clip();
47597 if(this.activePanel.beforeSlide){
47598 this.activePanel.beforeSlide();
47604 afterSlide : function(){
47605 if(Roo.isGecko){// firefox overflow auto bug workaround
47606 this.bodyEl.unclip();
47607 if(this.tabs) this.tabs.bodyEl.unclip();
47608 if(this.activePanel){
47609 this.activePanel.getEl().unclip();
47610 if(this.activePanel.afterSlide){
47611 this.activePanel.afterSlide();
47617 initAutoHide : function(){
47618 if(this.autoHide !== false){
47619 if(!this.autoHideHd){
47620 var st = new Roo.util.DelayedTask(this.slideIn, this);
47621 this.autoHideHd = {
47622 "mouseout": function(e){
47623 if(!e.within(this.el, true)){
47627 "mouseover" : function(e){
47633 this.el.on(this.autoHideHd);
47637 clearAutoHide : function(){
47638 if(this.autoHide !== false){
47639 this.el.un("mouseout", this.autoHideHd.mouseout);
47640 this.el.un("mouseover", this.autoHideHd.mouseover);
47644 clearMonitor : function(){
47645 Roo.get(document).un("click", this.slideInIf, this);
47648 // these names are backwards but not changed for compat
47649 slideOut : function(){
47650 if(this.isSlid || this.el.hasActiveFx()){
47653 this.isSlid = true;
47654 if(this.collapseBtn){
47655 this.collapseBtn.hide();
47657 this.closeBtnState = this.closeBtn.getStyle('display');
47658 this.closeBtn.hide();
47660 this.stickBtn.show();
47663 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
47664 this.beforeSlide();
47665 this.el.setStyle("z-index", 10001);
47666 this.el.slideIn(this.getSlideAnchor(), {
47667 callback: function(){
47669 this.initAutoHide();
47670 Roo.get(document).on("click", this.slideInIf, this);
47671 this.fireEvent("slideshow", this);
47678 afterSlideIn : function(){
47679 this.clearAutoHide();
47680 this.isSlid = false;
47681 this.clearMonitor();
47682 this.el.setStyle("z-index", "");
47683 if(this.collapseBtn){
47684 this.collapseBtn.show();
47686 this.closeBtn.setStyle('display', this.closeBtnState);
47688 this.stickBtn.hide();
47690 this.fireEvent("slidehide", this);
47693 slideIn : function(cb){
47694 if(!this.isSlid || this.el.hasActiveFx()){
47698 this.isSlid = false;
47699 this.beforeSlide();
47700 this.el.slideOut(this.getSlideAnchor(), {
47701 callback: function(){
47702 this.el.setLeftTop(-10000, -10000);
47704 this.afterSlideIn();
47712 slideInIf : function(e){
47713 if(!e.within(this.el)){
47718 animateCollapse : function(){
47719 this.beforeSlide();
47720 this.el.setStyle("z-index", 20000);
47721 var anchor = this.getSlideAnchor();
47722 this.el.slideOut(anchor, {
47723 callback : function(){
47724 this.el.setStyle("z-index", "");
47725 this.collapsedEl.slideIn(anchor, {duration:.3});
47727 this.el.setLocation(-10000,-10000);
47729 this.fireEvent("collapsed", this);
47736 animateExpand : function(){
47737 this.beforeSlide();
47738 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
47739 this.el.setStyle("z-index", 20000);
47740 this.collapsedEl.hide({
47743 this.el.slideIn(this.getSlideAnchor(), {
47744 callback : function(){
47745 this.el.setStyle("z-index", "");
47748 this.split.el.show();
47750 this.fireEvent("invalidated", this);
47751 this.fireEvent("expanded", this);
47779 getAnchor : function(){
47780 return this.anchors[this.position];
47783 getCollapseAnchor : function(){
47784 return this.canchors[this.position];
47787 getSlideAnchor : function(){
47788 return this.sanchors[this.position];
47791 getAlignAdj : function(){
47792 var cm = this.cmargins;
47793 switch(this.position){
47809 getExpandAdj : function(){
47810 var c = this.collapsedEl, cm = this.cmargins;
47811 switch(this.position){
47813 return [-(cm.right+c.getWidth()+cm.left), 0];
47816 return [cm.right+c.getWidth()+cm.left, 0];
47819 return [0, -(cm.top+cm.bottom+c.getHeight())];
47822 return [0, cm.top+cm.bottom+c.getHeight()];
47828 * Ext JS Library 1.1.1
47829 * Copyright(c) 2006-2007, Ext JS, LLC.
47831 * Originally Released Under LGPL - original licence link has changed is not relivant.
47834 * <script type="text/javascript">
47837 * These classes are private internal classes
47839 Roo.CenterLayoutRegion = function(mgr, config){
47840 Roo.LayoutRegion.call(this, mgr, config, "center");
47841 this.visible = true;
47842 this.minWidth = config.minWidth || 20;
47843 this.minHeight = config.minHeight || 20;
47846 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
47848 // center panel can't be hidden
47852 // center panel can't be hidden
47855 getMinWidth: function(){
47856 return this.minWidth;
47859 getMinHeight: function(){
47860 return this.minHeight;
47865 Roo.NorthLayoutRegion = function(mgr, config){
47866 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
47868 this.split.placement = Roo.SplitBar.TOP;
47869 this.split.orientation = Roo.SplitBar.VERTICAL;
47870 this.split.el.addClass("x-layout-split-v");
47872 var size = config.initialSize || config.height;
47873 if(typeof size != "undefined"){
47874 this.el.setHeight(size);
47877 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
47878 orientation: Roo.SplitBar.VERTICAL,
47879 getBox : function(){
47880 if(this.collapsed){
47881 return this.collapsedEl.getBox();
47883 var box = this.el.getBox();
47885 box.height += this.split.el.getHeight();
47890 updateBox : function(box){
47891 if(this.split && !this.collapsed){
47892 box.height -= this.split.el.getHeight();
47893 this.split.el.setLeft(box.x);
47894 this.split.el.setTop(box.y+box.height);
47895 this.split.el.setWidth(box.width);
47897 if(this.collapsed){
47898 this.updateBody(box.width, null);
47900 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47904 Roo.SouthLayoutRegion = function(mgr, config){
47905 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
47907 this.split.placement = Roo.SplitBar.BOTTOM;
47908 this.split.orientation = Roo.SplitBar.VERTICAL;
47909 this.split.el.addClass("x-layout-split-v");
47911 var size = config.initialSize || config.height;
47912 if(typeof size != "undefined"){
47913 this.el.setHeight(size);
47916 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
47917 orientation: Roo.SplitBar.VERTICAL,
47918 getBox : function(){
47919 if(this.collapsed){
47920 return this.collapsedEl.getBox();
47922 var box = this.el.getBox();
47924 var sh = this.split.el.getHeight();
47931 updateBox : function(box){
47932 if(this.split && !this.collapsed){
47933 var sh = this.split.el.getHeight();
47936 this.split.el.setLeft(box.x);
47937 this.split.el.setTop(box.y-sh);
47938 this.split.el.setWidth(box.width);
47940 if(this.collapsed){
47941 this.updateBody(box.width, null);
47943 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47947 Roo.EastLayoutRegion = function(mgr, config){
47948 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
47950 this.split.placement = Roo.SplitBar.RIGHT;
47951 this.split.orientation = Roo.SplitBar.HORIZONTAL;
47952 this.split.el.addClass("x-layout-split-h");
47954 var size = config.initialSize || config.width;
47955 if(typeof size != "undefined"){
47956 this.el.setWidth(size);
47959 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
47960 orientation: Roo.SplitBar.HORIZONTAL,
47961 getBox : function(){
47962 if(this.collapsed){
47963 return this.collapsedEl.getBox();
47965 var box = this.el.getBox();
47967 var sw = this.split.el.getWidth();
47974 updateBox : function(box){
47975 if(this.split && !this.collapsed){
47976 var sw = this.split.el.getWidth();
47978 this.split.el.setLeft(box.x);
47979 this.split.el.setTop(box.y);
47980 this.split.el.setHeight(box.height);
47983 if(this.collapsed){
47984 this.updateBody(null, box.height);
47986 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47990 Roo.WestLayoutRegion = function(mgr, config){
47991 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
47993 this.split.placement = Roo.SplitBar.LEFT;
47994 this.split.orientation = Roo.SplitBar.HORIZONTAL;
47995 this.split.el.addClass("x-layout-split-h");
47997 var size = config.initialSize || config.width;
47998 if(typeof size != "undefined"){
47999 this.el.setWidth(size);
48002 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
48003 orientation: Roo.SplitBar.HORIZONTAL,
48004 getBox : function(){
48005 if(this.collapsed){
48006 return this.collapsedEl.getBox();
48008 var box = this.el.getBox();
48010 box.width += this.split.el.getWidth();
48015 updateBox : function(box){
48016 if(this.split && !this.collapsed){
48017 var sw = this.split.el.getWidth();
48019 this.split.el.setLeft(box.x+box.width);
48020 this.split.el.setTop(box.y);
48021 this.split.el.setHeight(box.height);
48023 if(this.collapsed){
48024 this.updateBody(null, box.height);
48026 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48031 * Ext JS Library 1.1.1
48032 * Copyright(c) 2006-2007, Ext JS, LLC.
48034 * Originally Released Under LGPL - original licence link has changed is not relivant.
48037 * <script type="text/javascript">
48042 * Private internal class for reading and applying state
48044 Roo.LayoutStateManager = function(layout){
48045 // default empty state
48054 Roo.LayoutStateManager.prototype = {
48055 init : function(layout, provider){
48056 this.provider = provider;
48057 var state = provider.get(layout.id+"-layout-state");
48059 var wasUpdating = layout.isUpdating();
48061 layout.beginUpdate();
48063 for(var key in state){
48064 if(typeof state[key] != "function"){
48065 var rstate = state[key];
48066 var r = layout.getRegion(key);
48069 r.resizeTo(rstate.size);
48071 if(rstate.collapsed == true){
48074 r.expand(null, true);
48080 layout.endUpdate();
48082 this.state = state;
48084 this.layout = layout;
48085 layout.on("regionresized", this.onRegionResized, this);
48086 layout.on("regioncollapsed", this.onRegionCollapsed, this);
48087 layout.on("regionexpanded", this.onRegionExpanded, this);
48090 storeState : function(){
48091 this.provider.set(this.layout.id+"-layout-state", this.state);
48094 onRegionResized : function(region, newSize){
48095 this.state[region.getPosition()].size = newSize;
48099 onRegionCollapsed : function(region){
48100 this.state[region.getPosition()].collapsed = true;
48104 onRegionExpanded : function(region){
48105 this.state[region.getPosition()].collapsed = false;
48110 * Ext JS Library 1.1.1
48111 * Copyright(c) 2006-2007, Ext JS, LLC.
48113 * Originally Released Under LGPL - original licence link has changed is not relivant.
48116 * <script type="text/javascript">
48119 * @class Roo.ContentPanel
48120 * @extends Roo.util.Observable
48121 * A basic ContentPanel element.
48122 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
48123 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
48124 * @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
48125 * @cfg {Boolean} closable True if the panel can be closed/removed
48126 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
48127 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
48128 * @cfg {Toolbar} toolbar A toolbar for this panel
48129 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
48130 * @cfg {String} title The title for this panel
48131 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
48132 * @cfg {String} url Calls {@link #setUrl} with this value
48133 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
48134 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
48135 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
48136 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
48139 * Create a new ContentPanel.
48140 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
48141 * @param {String/Object} config A string to set only the title or a config object
48142 * @param {String} content (optional) Set the HTML content for this panel
48143 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
48145 Roo.ContentPanel = function(el, config, content){
48149 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
48153 if (config && config.parentLayout) {
48154 el = config.parentLayout.el.createChild();
48157 if(el.autoCreate){ // xtype is available if this is called from factory
48161 this.el = Roo.get(el);
48162 if(!this.el && config && config.autoCreate){
48163 if(typeof config.autoCreate == "object"){
48164 if(!config.autoCreate.id){
48165 config.autoCreate.id = config.id||el;
48167 this.el = Roo.DomHelper.append(document.body,
48168 config.autoCreate, true);
48170 this.el = Roo.DomHelper.append(document.body,
48171 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
48174 this.closable = false;
48175 this.loaded = false;
48176 this.active = false;
48177 if(typeof config == "string"){
48178 this.title = config;
48180 Roo.apply(this, config);
48183 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
48184 this.wrapEl = this.el.wrap();
48185 this.toolbar.container = this.el.insertSibling(false, 'before');
48186 this.toolbar = new Roo.Toolbar(this.toolbar);
48189 // xtype created footer. - not sure if will work as we normally have to render first..
48190 if (this.footer && !this.footer.el && this.footer.xtype) {
48191 if (!this.wrapEl) {
48192 this.wrapEl = this.el.wrap();
48195 this.footer.container = this.wrapEl.createChild();
48197 this.footer = Roo.factory(this.footer, Roo);
48202 this.resizeEl = Roo.get(this.resizeEl, true);
48204 this.resizeEl = this.el;
48209 * Fires when this panel is activated.
48210 * @param {Roo.ContentPanel} this
48214 * @event deactivate
48215 * Fires when this panel is activated.
48216 * @param {Roo.ContentPanel} this
48218 "deactivate" : true,
48222 * Fires when this panel is resized if fitToFrame is true.
48223 * @param {Roo.ContentPanel} this
48224 * @param {Number} width The width after any component adjustments
48225 * @param {Number} height The height after any component adjustments
48231 * Fires when this tab is created
48232 * @param {Roo.ContentPanel} this
48239 if(this.autoScroll){
48240 this.resizeEl.setStyle("overflow", "auto");
48242 // fix randome scrolling
48243 this.el.on('scroll', function() {
48244 Roo.log('fix random scolling');
48245 this.scrollTo('top',0);
48248 content = content || this.content;
48250 this.setContent(content);
48252 if(config && config.url){
48253 this.setUrl(this.url, this.params, this.loadOnce);
48258 Roo.ContentPanel.superclass.constructor.call(this);
48260 this.fireEvent('render', this);
48263 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
48265 setRegion : function(region){
48266 this.region = region;
48268 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
48270 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
48275 * Returns the toolbar for this Panel if one was configured.
48276 * @return {Roo.Toolbar}
48278 getToolbar : function(){
48279 return this.toolbar;
48282 setActiveState : function(active){
48283 this.active = active;
48285 this.fireEvent("deactivate", this);
48287 this.fireEvent("activate", this);
48291 * Updates this panel's element
48292 * @param {String} content The new content
48293 * @param {Boolean} loadScripts (optional) true to look for and process scripts
48295 setContent : function(content, loadScripts){
48296 this.el.update(content, loadScripts);
48299 ignoreResize : function(w, h){
48300 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
48303 this.lastSize = {width: w, height: h};
48308 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
48309 * @return {Roo.UpdateManager} The UpdateManager
48311 getUpdateManager : function(){
48312 return this.el.getUpdateManager();
48315 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
48316 * @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:
48319 url: "your-url.php",
48320 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
48321 callback: yourFunction,
48322 scope: yourObject, //(optional scope)
48325 text: "Loading...",
48330 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
48331 * 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.
48332 * @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}
48333 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
48334 * @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.
48335 * @return {Roo.ContentPanel} this
48338 var um = this.el.getUpdateManager();
48339 um.update.apply(um, arguments);
48345 * 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.
48346 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
48347 * @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)
48348 * @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)
48349 * @return {Roo.UpdateManager} The UpdateManager
48351 setUrl : function(url, params, loadOnce){
48352 if(this.refreshDelegate){
48353 this.removeListener("activate", this.refreshDelegate);
48355 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
48356 this.on("activate", this.refreshDelegate);
48357 return this.el.getUpdateManager();
48360 _handleRefresh : function(url, params, loadOnce){
48361 if(!loadOnce || !this.loaded){
48362 var updater = this.el.getUpdateManager();
48363 updater.update(url, params, this._setLoaded.createDelegate(this));
48367 _setLoaded : function(){
48368 this.loaded = true;
48372 * Returns this panel's id
48375 getId : function(){
48380 * Returns this panel's element - used by regiosn to add.
48381 * @return {Roo.Element}
48383 getEl : function(){
48384 return this.wrapEl || this.el;
48387 adjustForComponents : function(width, height)
48389 Roo.log('adjustForComponents ');
48390 if(this.resizeEl != this.el){
48391 width -= this.el.getFrameWidth('lr');
48392 height -= this.el.getFrameWidth('tb');
48395 var te = this.toolbar.getEl();
48396 height -= te.getHeight();
48397 te.setWidth(width);
48400 var te = this.footer.getEl();
48401 Roo.log("footer:" + te.getHeight());
48403 height -= te.getHeight();
48404 te.setWidth(width);
48408 if(this.adjustments){
48409 width += this.adjustments[0];
48410 height += this.adjustments[1];
48412 return {"width": width, "height": height};
48415 setSize : function(width, height){
48416 if(this.fitToFrame && !this.ignoreResize(width, height)){
48417 if(this.fitContainer && this.resizeEl != this.el){
48418 this.el.setSize(width, height);
48420 var size = this.adjustForComponents(width, height);
48421 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
48422 this.fireEvent('resize', this, size.width, size.height);
48427 * Returns this panel's title
48430 getTitle : function(){
48435 * Set this panel's title
48436 * @param {String} title
48438 setTitle : function(title){
48439 this.title = title;
48441 this.region.updatePanelTitle(this, title);
48446 * Returns true is this panel was configured to be closable
48447 * @return {Boolean}
48449 isClosable : function(){
48450 return this.closable;
48453 beforeSlide : function(){
48455 this.resizeEl.clip();
48458 afterSlide : function(){
48460 this.resizeEl.unclip();
48464 * Force a content refresh from the URL specified in the {@link #setUrl} method.
48465 * Will fail silently if the {@link #setUrl} method has not been called.
48466 * This does not activate the panel, just updates its content.
48468 refresh : function(){
48469 if(this.refreshDelegate){
48470 this.loaded = false;
48471 this.refreshDelegate();
48476 * Destroys this panel
48478 destroy : function(){
48479 this.el.removeAllListeners();
48480 var tempEl = document.createElement("span");
48481 tempEl.appendChild(this.el.dom);
48482 tempEl.innerHTML = "";
48488 * form - if the content panel contains a form - this is a reference to it.
48489 * @type {Roo.form.Form}
48493 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
48494 * This contains a reference to it.
48500 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
48510 * @param {Object} cfg Xtype definition of item to add.
48513 addxtype : function(cfg) {
48515 if (cfg.xtype.match(/^Form$/)) {
48518 //if (this.footer) {
48519 // el = this.footer.container.insertSibling(false, 'before');
48521 el = this.el.createChild();
48524 this.form = new Roo.form.Form(cfg);
48527 if ( this.form.allItems.length) this.form.render(el.dom);
48530 // should only have one of theses..
48531 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
48533 cfg.el = this.el.appendChild(document.createElement("div"));
48536 var ret = new Roo.factory(cfg);
48537 ret.render && ret.render(false, ''); // render blank..
48546 * @class Roo.GridPanel
48547 * @extends Roo.ContentPanel
48549 * Create a new GridPanel.
48550 * @param {Roo.grid.Grid} grid The grid for this panel
48551 * @param {String/Object} config A string to set only the panel's title, or a config object
48553 Roo.GridPanel = function(grid, config){
48556 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
48557 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
48559 this.wrapper.dom.appendChild(grid.getGridEl().dom);
48561 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
48564 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
48566 // xtype created footer. - not sure if will work as we normally have to render first..
48567 if (this.footer && !this.footer.el && this.footer.xtype) {
48569 this.footer.container = this.grid.getView().getFooterPanel(true);
48570 this.footer.dataSource = this.grid.dataSource;
48571 this.footer = Roo.factory(this.footer, Roo);
48575 grid.monitorWindowResize = false; // turn off autosizing
48576 grid.autoHeight = false;
48577 grid.autoWidth = false;
48579 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
48582 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
48583 getId : function(){
48584 return this.grid.id;
48588 * Returns the grid for this panel
48589 * @return {Roo.grid.Grid}
48591 getGrid : function(){
48595 setSize : function(width, height){
48596 if(!this.ignoreResize(width, height)){
48597 var grid = this.grid;
48598 var size = this.adjustForComponents(width, height);
48599 grid.getGridEl().setSize(size.width, size.height);
48604 beforeSlide : function(){
48605 this.grid.getView().scroller.clip();
48608 afterSlide : function(){
48609 this.grid.getView().scroller.unclip();
48612 destroy : function(){
48613 this.grid.destroy();
48615 Roo.GridPanel.superclass.destroy.call(this);
48621 * @class Roo.NestedLayoutPanel
48622 * @extends Roo.ContentPanel
48624 * Create a new NestedLayoutPanel.
48627 * @param {Roo.BorderLayout} layout The layout for this panel
48628 * @param {String/Object} config A string to set only the title or a config object
48630 Roo.NestedLayoutPanel = function(layout, config)
48632 // construct with only one argument..
48633 /* FIXME - implement nicer consturctors
48634 if (layout.layout) {
48636 layout = config.layout;
48637 delete config.layout;
48639 if (layout.xtype && !layout.getEl) {
48640 // then layout needs constructing..
48641 layout = Roo.factory(layout, Roo);
48646 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
48648 layout.monitorWindowResize = false; // turn off autosizing
48649 this.layout = layout;
48650 this.layout.getEl().addClass("x-layout-nested-layout");
48657 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
48659 setSize : function(width, height){
48660 if(!this.ignoreResize(width, height)){
48661 var size = this.adjustForComponents(width, height);
48662 var el = this.layout.getEl();
48663 el.setSize(size.width, size.height);
48664 var touch = el.dom.offsetWidth;
48665 this.layout.layout();
48666 // ie requires a double layout on the first pass
48667 if(Roo.isIE && !this.initialized){
48668 this.initialized = true;
48669 this.layout.layout();
48674 // activate all subpanels if not currently active..
48676 setActiveState : function(active){
48677 this.active = active;
48679 this.fireEvent("deactivate", this);
48683 this.fireEvent("activate", this);
48684 // not sure if this should happen before or after..
48685 if (!this.layout) {
48686 return; // should not happen..
48689 for (var r in this.layout.regions) {
48690 reg = this.layout.getRegion(r);
48691 if (reg.getActivePanel()) {
48692 //reg.showPanel(reg.getActivePanel()); // force it to activate..
48693 reg.setActivePanel(reg.getActivePanel());
48696 if (!reg.panels.length) {
48699 reg.showPanel(reg.getPanel(0));
48708 * Returns the nested BorderLayout for this panel
48709 * @return {Roo.BorderLayout}
48711 getLayout : function(){
48712 return this.layout;
48716 * Adds a xtype elements to the layout of the nested panel
48720 xtype : 'ContentPanel',
48727 xtype : 'NestedLayoutPanel',
48733 items : [ ... list of content panels or nested layout panels.. ]
48737 * @param {Object} cfg Xtype definition of item to add.
48739 addxtype : function(cfg) {
48740 return this.layout.addxtype(cfg);
48745 Roo.ScrollPanel = function(el, config, content){
48746 config = config || {};
48747 config.fitToFrame = true;
48748 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
48750 this.el.dom.style.overflow = "hidden";
48751 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
48752 this.el.removeClass("x-layout-inactive-content");
48753 this.el.on("mousewheel", this.onWheel, this);
48755 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
48756 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
48757 up.unselectable(); down.unselectable();
48758 up.on("click", this.scrollUp, this);
48759 down.on("click", this.scrollDown, this);
48760 up.addClassOnOver("x-scroller-btn-over");
48761 down.addClassOnOver("x-scroller-btn-over");
48762 up.addClassOnClick("x-scroller-btn-click");
48763 down.addClassOnClick("x-scroller-btn-click");
48764 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
48766 this.resizeEl = this.el;
48767 this.el = wrap; this.up = up; this.down = down;
48770 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
48772 wheelIncrement : 5,
48773 scrollUp : function(){
48774 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
48777 scrollDown : function(){
48778 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
48781 afterScroll : function(){
48782 var el = this.resizeEl;
48783 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
48784 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
48785 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
48788 setSize : function(){
48789 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
48790 this.afterScroll();
48793 onWheel : function(e){
48794 var d = e.getWheelDelta();
48795 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
48796 this.afterScroll();
48800 setContent : function(content, loadScripts){
48801 this.resizeEl.update(content, loadScripts);
48815 * @class Roo.TreePanel
48816 * @extends Roo.ContentPanel
48818 * Create a new TreePanel. - defaults to fit/scoll contents.
48819 * @param {String/Object} config A string to set only the panel's title, or a config object
48820 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
48822 Roo.TreePanel = function(config){
48823 var el = config.el;
48824 var tree = config.tree;
48825 delete config.tree;
48826 delete config.el; // hopefull!
48828 // wrapper for IE7 strict & safari scroll issue
48830 var treeEl = el.createChild();
48831 config.resizeEl = treeEl;
48835 Roo.TreePanel.superclass.constructor.call(this, el, config);
48838 this.tree = new Roo.tree.TreePanel(treeEl , tree);
48839 //console.log(tree);
48840 this.on('activate', function()
48842 if (this.tree.rendered) {
48845 //console.log('render tree');
48846 this.tree.render();
48848 // this should not be needed.. - it's actually the 'el' that resizes?
48849 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
48851 //this.on('resize', function (cp, w, h) {
48852 // this.tree.innerCt.setWidth(w);
48853 // this.tree.innerCt.setHeight(h);
48854 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
48861 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
48878 * Ext JS Library 1.1.1
48879 * Copyright(c) 2006-2007, Ext JS, LLC.
48881 * Originally Released Under LGPL - original licence link has changed is not relivant.
48884 * <script type="text/javascript">
48889 * @class Roo.ReaderLayout
48890 * @extends Roo.BorderLayout
48891 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
48892 * center region containing two nested regions (a top one for a list view and one for item preview below),
48893 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
48894 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
48895 * expedites the setup of the overall layout and regions for this common application style.
48898 var reader = new Roo.ReaderLayout();
48899 var CP = Roo.ContentPanel; // shortcut for adding
48901 reader.beginUpdate();
48902 reader.add("north", new CP("north", "North"));
48903 reader.add("west", new CP("west", {title: "West"}));
48904 reader.add("east", new CP("east", {title: "East"}));
48906 reader.regions.listView.add(new CP("listView", "List"));
48907 reader.regions.preview.add(new CP("preview", "Preview"));
48908 reader.endUpdate();
48911 * Create a new ReaderLayout
48912 * @param {Object} config Configuration options
48913 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
48914 * document.body if omitted)
48916 Roo.ReaderLayout = function(config, renderTo){
48917 var c = config || {size:{}};
48918 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
48919 north: c.north !== false ? Roo.apply({
48923 }, c.north) : false,
48924 west: c.west !== false ? Roo.apply({
48932 margins:{left:5,right:0,bottom:5,top:5},
48933 cmargins:{left:5,right:5,bottom:5,top:5}
48934 }, c.west) : false,
48935 east: c.east !== false ? Roo.apply({
48943 margins:{left:0,right:5,bottom:5,top:5},
48944 cmargins:{left:5,right:5,bottom:5,top:5}
48945 }, c.east) : false,
48946 center: Roo.apply({
48947 tabPosition: 'top',
48951 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
48955 this.el.addClass('x-reader');
48957 this.beginUpdate();
48959 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
48960 south: c.preview !== false ? Roo.apply({
48967 cmargins:{top:5,left:0, right:0, bottom:0}
48968 }, c.preview) : false,
48969 center: Roo.apply({
48975 this.add('center', new Roo.NestedLayoutPanel(inner,
48976 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
48980 this.regions.preview = inner.getRegion('south');
48981 this.regions.listView = inner.getRegion('center');
48984 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
48986 * Ext JS Library 1.1.1
48987 * Copyright(c) 2006-2007, Ext JS, LLC.
48989 * Originally Released Under LGPL - original licence link has changed is not relivant.
48992 * <script type="text/javascript">
48996 * @class Roo.grid.Grid
48997 * @extends Roo.util.Observable
48998 * This class represents the primary interface of a component based grid control.
48999 * <br><br>Usage:<pre><code>
49000 var grid = new Roo.grid.Grid("my-container-id", {
49003 selModel: mySelectionModel,
49004 autoSizeColumns: true,
49005 monitorWindowResize: false,
49006 trackMouseOver: true
49011 * <b>Common Problems:</b><br/>
49012 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
49013 * element will correct this<br/>
49014 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
49015 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
49016 * are unpredictable.<br/>
49017 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
49018 * grid to calculate dimensions/offsets.<br/>
49020 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49021 * The container MUST have some type of size defined for the grid to fill. The container will be
49022 * automatically set to position relative if it isn't already.
49023 * @param {Object} config A config object that sets properties on this grid.
49025 Roo.grid.Grid = function(container, config){
49026 // initialize the container
49027 this.container = Roo.get(container);
49028 this.container.update("");
49029 this.container.setStyle("overflow", "hidden");
49030 this.container.addClass('x-grid-container');
49032 this.id = this.container.id;
49034 Roo.apply(this, config);
49035 // check and correct shorthanded configs
49037 this.dataSource = this.ds;
49041 this.colModel = this.cm;
49045 this.selModel = this.sm;
49049 if (this.selModel) {
49050 this.selModel = Roo.factory(this.selModel, Roo.grid);
49051 this.sm = this.selModel;
49052 this.sm.xmodule = this.xmodule || false;
49054 if (typeof(this.colModel.config) == 'undefined') {
49055 this.colModel = new Roo.grid.ColumnModel(this.colModel);
49056 this.cm = this.colModel;
49057 this.cm.xmodule = this.xmodule || false;
49059 if (this.dataSource) {
49060 this.dataSource= Roo.factory(this.dataSource, Roo.data);
49061 this.ds = this.dataSource;
49062 this.ds.xmodule = this.xmodule || false;
49069 this.container.setWidth(this.width);
49073 this.container.setHeight(this.height);
49080 * The raw click event for the entire grid.
49081 * @param {Roo.EventObject} e
49086 * The raw dblclick event for the entire grid.
49087 * @param {Roo.EventObject} e
49091 * @event contextmenu
49092 * The raw contextmenu event for the entire grid.
49093 * @param {Roo.EventObject} e
49095 "contextmenu" : true,
49098 * The raw mousedown event for the entire grid.
49099 * @param {Roo.EventObject} e
49101 "mousedown" : true,
49104 * The raw mouseup event for the entire grid.
49105 * @param {Roo.EventObject} e
49110 * The raw mouseover event for the entire grid.
49111 * @param {Roo.EventObject} e
49113 "mouseover" : true,
49116 * The raw mouseout event for the entire grid.
49117 * @param {Roo.EventObject} e
49122 * The raw keypress event for the entire grid.
49123 * @param {Roo.EventObject} e
49128 * The raw keydown event for the entire grid.
49129 * @param {Roo.EventObject} e
49137 * Fires when a cell is clicked
49138 * @param {Grid} this
49139 * @param {Number} rowIndex
49140 * @param {Number} columnIndex
49141 * @param {Roo.EventObject} e
49143 "cellclick" : true,
49145 * @event celldblclick
49146 * Fires when a cell is double clicked
49147 * @param {Grid} this
49148 * @param {Number} rowIndex
49149 * @param {Number} columnIndex
49150 * @param {Roo.EventObject} e
49152 "celldblclick" : true,
49155 * Fires when a row is clicked
49156 * @param {Grid} this
49157 * @param {Number} rowIndex
49158 * @param {Roo.EventObject} e
49162 * @event rowdblclick
49163 * Fires when a row is double clicked
49164 * @param {Grid} this
49165 * @param {Number} rowIndex
49166 * @param {Roo.EventObject} e
49168 "rowdblclick" : true,
49170 * @event headerclick
49171 * Fires when a header is clicked
49172 * @param {Grid} this
49173 * @param {Number} columnIndex
49174 * @param {Roo.EventObject} e
49176 "headerclick" : true,
49178 * @event headerdblclick
49179 * Fires when a header cell is double clicked
49180 * @param {Grid} this
49181 * @param {Number} columnIndex
49182 * @param {Roo.EventObject} e
49184 "headerdblclick" : true,
49186 * @event rowcontextmenu
49187 * Fires when a row is right clicked
49188 * @param {Grid} this
49189 * @param {Number} rowIndex
49190 * @param {Roo.EventObject} e
49192 "rowcontextmenu" : true,
49194 * @event cellcontextmenu
49195 * Fires when a cell is right clicked
49196 * @param {Grid} this
49197 * @param {Number} rowIndex
49198 * @param {Number} cellIndex
49199 * @param {Roo.EventObject} e
49201 "cellcontextmenu" : true,
49203 * @event headercontextmenu
49204 * Fires when a header is right clicked
49205 * @param {Grid} this
49206 * @param {Number} columnIndex
49207 * @param {Roo.EventObject} e
49209 "headercontextmenu" : true,
49211 * @event bodyscroll
49212 * Fires when the body element is scrolled
49213 * @param {Number} scrollLeft
49214 * @param {Number} scrollTop
49216 "bodyscroll" : true,
49218 * @event columnresize
49219 * Fires when the user resizes a column
49220 * @param {Number} columnIndex
49221 * @param {Number} newSize
49223 "columnresize" : true,
49225 * @event columnmove
49226 * Fires when the user moves a column
49227 * @param {Number} oldIndex
49228 * @param {Number} newIndex
49230 "columnmove" : true,
49233 * Fires when row(s) start being dragged
49234 * @param {Grid} this
49235 * @param {Roo.GridDD} dd The drag drop object
49236 * @param {event} e The raw browser event
49238 "startdrag" : true,
49241 * Fires when a drag operation is complete
49242 * @param {Grid} this
49243 * @param {Roo.GridDD} dd The drag drop object
49244 * @param {event} e The raw browser event
49249 * Fires when dragged row(s) are dropped on a valid DD target
49250 * @param {Grid} this
49251 * @param {Roo.GridDD} dd The drag drop object
49252 * @param {String} targetId The target drag drop object
49253 * @param {event} e The raw browser event
49258 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
49259 * @param {Grid} this
49260 * @param {Roo.GridDD} dd The drag drop object
49261 * @param {String} targetId The target drag drop object
49262 * @param {event} e The raw browser event
49267 * Fires when the dragged row(s) first cross another DD target while being dragged
49268 * @param {Grid} this
49269 * @param {Roo.GridDD} dd The drag drop object
49270 * @param {String} targetId The target drag drop object
49271 * @param {event} e The raw browser event
49273 "dragenter" : true,
49276 * Fires when the dragged row(s) leave another DD target while being dragged
49277 * @param {Grid} this
49278 * @param {Roo.GridDD} dd The drag drop object
49279 * @param {String} targetId The target drag drop object
49280 * @param {event} e The raw browser event
49285 * Fires when a row is rendered, so you can change add a style to it.
49286 * @param {GridView} gridview The grid view
49287 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
49293 * Fires when the grid is rendered
49294 * @param {Grid} grid
49299 Roo.grid.Grid.superclass.constructor.call(this);
49301 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
49304 * @cfg {String} ddGroup - drag drop group.
49308 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
49310 minColumnWidth : 25,
49313 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
49314 * <b>on initial render.</b> It is more efficient to explicitly size the columns
49315 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
49317 autoSizeColumns : false,
49320 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
49322 autoSizeHeaders : true,
49325 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
49327 monitorWindowResize : true,
49330 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
49331 * rows measured to get a columns size. Default is 0 (all rows).
49333 maxRowsToMeasure : 0,
49336 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
49338 trackMouseOver : true,
49341 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
49345 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
49347 enableDragDrop : false,
49350 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
49352 enableColumnMove : true,
49355 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
49357 enableColumnHide : true,
49360 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
49362 enableRowHeightSync : false,
49365 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
49370 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
49372 autoHeight : false,
49375 * @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.
49377 autoExpandColumn : false,
49380 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
49383 autoExpandMin : 50,
49386 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
49388 autoExpandMax : 1000,
49391 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
49396 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
49400 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
49410 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
49411 * of a fixed width. Default is false.
49414 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
49417 * Called once after all setup has been completed and the grid is ready to be rendered.
49418 * @return {Roo.grid.Grid} this
49420 render : function()
49422 var c = this.container;
49423 // try to detect autoHeight/width mode
49424 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
49425 this.autoHeight = true;
49427 var view = this.getView();
49430 c.on("click", this.onClick, this);
49431 c.on("dblclick", this.onDblClick, this);
49432 c.on("contextmenu", this.onContextMenu, this);
49433 c.on("keydown", this.onKeyDown, this);
49435 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
49437 this.getSelectionModel().init(this);
49442 this.loadMask = new Roo.LoadMask(this.container,
49443 Roo.apply({store:this.dataSource}, this.loadMask));
49447 if (this.toolbar && this.toolbar.xtype) {
49448 this.toolbar.container = this.getView().getHeaderPanel(true);
49449 this.toolbar = new Roo.Toolbar(this.toolbar);
49451 if (this.footer && this.footer.xtype) {
49452 this.footer.dataSource = this.getDataSource();
49453 this.footer.container = this.getView().getFooterPanel(true);
49454 this.footer = Roo.factory(this.footer, Roo);
49456 if (this.dropTarget && this.dropTarget.xtype) {
49457 delete this.dropTarget.xtype;
49458 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
49462 this.rendered = true;
49463 this.fireEvent('render', this);
49468 * Reconfigures the grid to use a different Store and Column Model.
49469 * The View will be bound to the new objects and refreshed.
49470 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
49471 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
49473 reconfigure : function(dataSource, colModel){
49475 this.loadMask.destroy();
49476 this.loadMask = new Roo.LoadMask(this.container,
49477 Roo.apply({store:dataSource}, this.loadMask));
49479 this.view.bind(dataSource, colModel);
49480 this.dataSource = dataSource;
49481 this.colModel = colModel;
49482 this.view.refresh(true);
49486 onKeyDown : function(e){
49487 this.fireEvent("keydown", e);
49491 * Destroy this grid.
49492 * @param {Boolean} removeEl True to remove the element
49494 destroy : function(removeEl, keepListeners){
49496 this.loadMask.destroy();
49498 var c = this.container;
49499 c.removeAllListeners();
49500 this.view.destroy();
49501 this.colModel.purgeListeners();
49502 if(!keepListeners){
49503 this.purgeListeners();
49506 if(removeEl === true){
49512 processEvent : function(name, e){
49513 this.fireEvent(name, e);
49514 var t = e.getTarget();
49516 var header = v.findHeaderIndex(t);
49517 if(header !== false){
49518 this.fireEvent("header" + name, this, header, e);
49520 var row = v.findRowIndex(t);
49521 var cell = v.findCellIndex(t);
49523 this.fireEvent("row" + name, this, row, e);
49524 if(cell !== false){
49525 this.fireEvent("cell" + name, this, row, cell, e);
49532 onClick : function(e){
49533 this.processEvent("click", e);
49537 onContextMenu : function(e, t){
49538 this.processEvent("contextmenu", e);
49542 onDblClick : function(e){
49543 this.processEvent("dblclick", e);
49547 walkCells : function(row, col, step, fn, scope){
49548 var cm = this.colModel, clen = cm.getColumnCount();
49549 var ds = this.dataSource, rlen = ds.getCount(), first = true;
49561 if(fn.call(scope || this, row, col, cm) === true){
49579 if(fn.call(scope || this, row, col, cm) === true){
49591 getSelections : function(){
49592 return this.selModel.getSelections();
49596 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
49597 * but if manual update is required this method will initiate it.
49599 autoSize : function(){
49601 this.view.layout();
49602 if(this.view.adjustForScroll){
49603 this.view.adjustForScroll();
49609 * Returns the grid's underlying element.
49610 * @return {Element} The element
49612 getGridEl : function(){
49613 return this.container;
49616 // private for compatibility, overridden by editor grid
49617 stopEditing : function(){},
49620 * Returns the grid's SelectionModel.
49621 * @return {SelectionModel}
49623 getSelectionModel : function(){
49624 if(!this.selModel){
49625 this.selModel = new Roo.grid.RowSelectionModel();
49627 return this.selModel;
49631 * Returns the grid's DataSource.
49632 * @return {DataSource}
49634 getDataSource : function(){
49635 return this.dataSource;
49639 * Returns the grid's ColumnModel.
49640 * @return {ColumnModel}
49642 getColumnModel : function(){
49643 return this.colModel;
49647 * Returns the grid's GridView object.
49648 * @return {GridView}
49650 getView : function(){
49652 this.view = new Roo.grid.GridView(this.viewConfig);
49657 * Called to get grid's drag proxy text, by default returns this.ddText.
49660 getDragDropText : function(){
49661 var count = this.selModel.getCount();
49662 return String.format(this.ddText, count, count == 1 ? '' : 's');
49666 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
49667 * %0 is replaced with the number of selected rows.
49670 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
49672 * Ext JS Library 1.1.1
49673 * Copyright(c) 2006-2007, Ext JS, LLC.
49675 * Originally Released Under LGPL - original licence link has changed is not relivant.
49678 * <script type="text/javascript">
49681 Roo.grid.AbstractGridView = function(){
49685 "beforerowremoved" : true,
49686 "beforerowsinserted" : true,
49687 "beforerefresh" : true,
49688 "rowremoved" : true,
49689 "rowsinserted" : true,
49690 "rowupdated" : true,
49693 Roo.grid.AbstractGridView.superclass.constructor.call(this);
49696 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
49697 rowClass : "x-grid-row",
49698 cellClass : "x-grid-cell",
49699 tdClass : "x-grid-td",
49700 hdClass : "x-grid-hd",
49701 splitClass : "x-grid-hd-split",
49703 init: function(grid){
49705 var cid = this.grid.getGridEl().id;
49706 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
49707 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
49708 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
49709 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
49712 getColumnRenderers : function(){
49713 var renderers = [];
49714 var cm = this.grid.colModel;
49715 var colCount = cm.getColumnCount();
49716 for(var i = 0; i < colCount; i++){
49717 renderers[i] = cm.getRenderer(i);
49722 getColumnIds : function(){
49724 var cm = this.grid.colModel;
49725 var colCount = cm.getColumnCount();
49726 for(var i = 0; i < colCount; i++){
49727 ids[i] = cm.getColumnId(i);
49732 getDataIndexes : function(){
49733 if(!this.indexMap){
49734 this.indexMap = this.buildIndexMap();
49736 return this.indexMap.colToData;
49739 getColumnIndexByDataIndex : function(dataIndex){
49740 if(!this.indexMap){
49741 this.indexMap = this.buildIndexMap();
49743 return this.indexMap.dataToCol[dataIndex];
49747 * Set a css style for a column dynamically.
49748 * @param {Number} colIndex The index of the column
49749 * @param {String} name The css property name
49750 * @param {String} value The css value
49752 setCSSStyle : function(colIndex, name, value){
49753 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
49754 Roo.util.CSS.updateRule(selector, name, value);
49757 generateRules : function(cm){
49758 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
49759 Roo.util.CSS.removeStyleSheet(rulesId);
49760 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49761 var cid = cm.getColumnId(i);
49762 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
49763 this.tdSelector, cid, " {\n}\n",
49764 this.hdSelector, cid, " {\n}\n",
49765 this.splitSelector, cid, " {\n}\n");
49767 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
49771 * Ext JS Library 1.1.1
49772 * Copyright(c) 2006-2007, Ext JS, LLC.
49774 * Originally Released Under LGPL - original licence link has changed is not relivant.
49777 * <script type="text/javascript">
49781 // This is a support class used internally by the Grid components
49782 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
49784 this.view = grid.getView();
49785 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
49786 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
49788 this.setHandleElId(Roo.id(hd));
49789 this.setOuterHandleElId(Roo.id(hd2));
49791 this.scroll = false;
49793 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
49795 getDragData : function(e){
49796 var t = Roo.lib.Event.getTarget(e);
49797 var h = this.view.findHeaderCell(t);
49799 return {ddel: h.firstChild, header:h};
49804 onInitDrag : function(e){
49805 this.view.headersDisabled = true;
49806 var clone = this.dragData.ddel.cloneNode(true);
49807 clone.id = Roo.id();
49808 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
49809 this.proxy.update(clone);
49813 afterValidDrop : function(){
49815 setTimeout(function(){
49816 v.headersDisabled = false;
49820 afterInvalidDrop : function(){
49822 setTimeout(function(){
49823 v.headersDisabled = false;
49829 * Ext JS Library 1.1.1
49830 * Copyright(c) 2006-2007, Ext JS, LLC.
49832 * Originally Released Under LGPL - original licence link has changed is not relivant.
49835 * <script type="text/javascript">
49838 // This is a support class used internally by the Grid components
49839 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
49841 this.view = grid.getView();
49842 // split the proxies so they don't interfere with mouse events
49843 this.proxyTop = Roo.DomHelper.append(document.body, {
49844 cls:"col-move-top", html:" "
49846 this.proxyBottom = Roo.DomHelper.append(document.body, {
49847 cls:"col-move-bottom", html:" "
49849 this.proxyTop.hide = this.proxyBottom.hide = function(){
49850 this.setLeftTop(-100,-100);
49851 this.setStyle("visibility", "hidden");
49853 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
49854 // temporarily disabled
49855 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
49856 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
49858 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
49859 proxyOffsets : [-4, -9],
49860 fly: Roo.Element.fly,
49862 getTargetFromEvent : function(e){
49863 var t = Roo.lib.Event.getTarget(e);
49864 var cindex = this.view.findCellIndex(t);
49865 if(cindex !== false){
49866 return this.view.getHeaderCell(cindex);
49871 nextVisible : function(h){
49872 var v = this.view, cm = this.grid.colModel;
49875 if(!cm.isHidden(v.getCellIndex(h))){
49883 prevVisible : function(h){
49884 var v = this.view, cm = this.grid.colModel;
49887 if(!cm.isHidden(v.getCellIndex(h))){
49895 positionIndicator : function(h, n, e){
49896 var x = Roo.lib.Event.getPageX(e);
49897 var r = Roo.lib.Dom.getRegion(n.firstChild);
49898 var px, pt, py = r.top + this.proxyOffsets[1];
49899 if((r.right - x) <= (r.right-r.left)/2){
49900 px = r.right+this.view.borderWidth;
49906 var oldIndex = this.view.getCellIndex(h);
49907 var newIndex = this.view.getCellIndex(n);
49909 if(this.grid.colModel.isFixed(newIndex)){
49913 var locked = this.grid.colModel.isLocked(newIndex);
49918 if(oldIndex < newIndex){
49921 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
49924 px += this.proxyOffsets[0];
49925 this.proxyTop.setLeftTop(px, py);
49926 this.proxyTop.show();
49927 if(!this.bottomOffset){
49928 this.bottomOffset = this.view.mainHd.getHeight();
49930 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
49931 this.proxyBottom.show();
49935 onNodeEnter : function(n, dd, e, data){
49936 if(data.header != n){
49937 this.positionIndicator(data.header, n, e);
49941 onNodeOver : function(n, dd, e, data){
49942 var result = false;
49943 if(data.header != n){
49944 result = this.positionIndicator(data.header, n, e);
49947 this.proxyTop.hide();
49948 this.proxyBottom.hide();
49950 return result ? this.dropAllowed : this.dropNotAllowed;
49953 onNodeOut : function(n, dd, e, data){
49954 this.proxyTop.hide();
49955 this.proxyBottom.hide();
49958 onNodeDrop : function(n, dd, e, data){
49959 var h = data.header;
49961 var cm = this.grid.colModel;
49962 var x = Roo.lib.Event.getPageX(e);
49963 var r = Roo.lib.Dom.getRegion(n.firstChild);
49964 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
49965 var oldIndex = this.view.getCellIndex(h);
49966 var newIndex = this.view.getCellIndex(n);
49967 var locked = cm.isLocked(newIndex);
49971 if(oldIndex < newIndex){
49974 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
49977 cm.setLocked(oldIndex, locked, true);
49978 cm.moveColumn(oldIndex, newIndex);
49979 this.grid.fireEvent("columnmove", oldIndex, newIndex);
49987 * Ext JS Library 1.1.1
49988 * Copyright(c) 2006-2007, Ext JS, LLC.
49990 * Originally Released Under LGPL - original licence link has changed is not relivant.
49993 * <script type="text/javascript">
49997 * @class Roo.grid.GridView
49998 * @extends Roo.util.Observable
50001 * @param {Object} config
50003 Roo.grid.GridView = function(config){
50004 Roo.grid.GridView.superclass.constructor.call(this);
50007 Roo.apply(this, config);
50010 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
50013 rowClass : "x-grid-row",
50015 cellClass : "x-grid-col",
50017 tdClass : "x-grid-td",
50019 hdClass : "x-grid-hd",
50021 splitClass : "x-grid-split",
50023 sortClasses : ["sort-asc", "sort-desc"],
50025 enableMoveAnim : false,
50029 dh : Roo.DomHelper,
50031 fly : Roo.Element.fly,
50033 css : Roo.util.CSS,
50039 scrollIncrement : 22,
50041 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
50043 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
50045 bind : function(ds, cm){
50047 this.ds.un("load", this.onLoad, this);
50048 this.ds.un("datachanged", this.onDataChange, this);
50049 this.ds.un("add", this.onAdd, this);
50050 this.ds.un("remove", this.onRemove, this);
50051 this.ds.un("update", this.onUpdate, this);
50052 this.ds.un("clear", this.onClear, this);
50055 ds.on("load", this.onLoad, this);
50056 ds.on("datachanged", this.onDataChange, this);
50057 ds.on("add", this.onAdd, this);
50058 ds.on("remove", this.onRemove, this);
50059 ds.on("update", this.onUpdate, this);
50060 ds.on("clear", this.onClear, this);
50065 this.cm.un("widthchange", this.onColWidthChange, this);
50066 this.cm.un("headerchange", this.onHeaderChange, this);
50067 this.cm.un("hiddenchange", this.onHiddenChange, this);
50068 this.cm.un("columnmoved", this.onColumnMove, this);
50069 this.cm.un("columnlockchange", this.onColumnLock, this);
50072 this.generateRules(cm);
50073 cm.on("widthchange", this.onColWidthChange, this);
50074 cm.on("headerchange", this.onHeaderChange, this);
50075 cm.on("hiddenchange", this.onHiddenChange, this);
50076 cm.on("columnmoved", this.onColumnMove, this);
50077 cm.on("columnlockchange", this.onColumnLock, this);
50082 init: function(grid){
50083 Roo.grid.GridView.superclass.init.call(this, grid);
50085 this.bind(grid.dataSource, grid.colModel);
50087 grid.on("headerclick", this.handleHeaderClick, this);
50089 if(grid.trackMouseOver){
50090 grid.on("mouseover", this.onRowOver, this);
50091 grid.on("mouseout", this.onRowOut, this);
50093 grid.cancelTextSelection = function(){};
50094 this.gridId = grid.id;
50096 var tpls = this.templates || {};
50099 tpls.master = new Roo.Template(
50100 '<div class="x-grid" hidefocus="true">',
50101 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
50102 '<div class="x-grid-topbar"></div>',
50103 '<div class="x-grid-scroller"><div></div></div>',
50104 '<div class="x-grid-locked">',
50105 '<div class="x-grid-header">{lockedHeader}</div>',
50106 '<div class="x-grid-body">{lockedBody}</div>',
50108 '<div class="x-grid-viewport">',
50109 '<div class="x-grid-header">{header}</div>',
50110 '<div class="x-grid-body">{body}</div>',
50112 '<div class="x-grid-bottombar"></div>',
50114 '<div class="x-grid-resize-proxy"> </div>',
50117 tpls.master.disableformats = true;
50121 tpls.header = new Roo.Template(
50122 '<table border="0" cellspacing="0" cellpadding="0">',
50123 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
50126 tpls.header.disableformats = true;
50128 tpls.header.compile();
50131 tpls.hcell = new Roo.Template(
50132 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
50133 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
50136 tpls.hcell.disableFormats = true;
50138 tpls.hcell.compile();
50141 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
50142 tpls.hsplit.disableFormats = true;
50144 tpls.hsplit.compile();
50147 tpls.body = new Roo.Template(
50148 '<table border="0" cellspacing="0" cellpadding="0">',
50149 "<tbody>{rows}</tbody>",
50152 tpls.body.disableFormats = true;
50154 tpls.body.compile();
50157 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
50158 tpls.row.disableFormats = true;
50160 tpls.row.compile();
50163 tpls.cell = new Roo.Template(
50164 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
50165 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
50168 tpls.cell.disableFormats = true;
50170 tpls.cell.compile();
50172 this.templates = tpls;
50175 // remap these for backwards compat
50176 onColWidthChange : function(){
50177 this.updateColumns.apply(this, arguments);
50179 onHeaderChange : function(){
50180 this.updateHeaders.apply(this, arguments);
50182 onHiddenChange : function(){
50183 this.handleHiddenChange.apply(this, arguments);
50185 onColumnMove : function(){
50186 this.handleColumnMove.apply(this, arguments);
50188 onColumnLock : function(){
50189 this.handleLockChange.apply(this, arguments);
50192 onDataChange : function(){
50194 this.updateHeaderSortState();
50197 onClear : function(){
50201 onUpdate : function(ds, record){
50202 this.refreshRow(record);
50205 refreshRow : function(record){
50206 var ds = this.ds, index;
50207 if(typeof record == 'number'){
50209 record = ds.getAt(index);
50211 index = ds.indexOf(record);
50213 this.insertRows(ds, index, index, true);
50214 this.onRemove(ds, record, index+1, true);
50215 this.syncRowHeights(index, index);
50217 this.fireEvent("rowupdated", this, index, record);
50220 onAdd : function(ds, records, index){
50221 this.insertRows(ds, index, index + (records.length-1));
50224 onRemove : function(ds, record, index, isUpdate){
50225 if(isUpdate !== true){
50226 this.fireEvent("beforerowremoved", this, index, record);
50228 var bt = this.getBodyTable(), lt = this.getLockedTable();
50229 if(bt.rows[index]){
50230 bt.firstChild.removeChild(bt.rows[index]);
50232 if(lt.rows[index]){
50233 lt.firstChild.removeChild(lt.rows[index]);
50235 if(isUpdate !== true){
50236 this.stripeRows(index);
50237 this.syncRowHeights(index, index);
50239 this.fireEvent("rowremoved", this, index, record);
50243 onLoad : function(){
50244 this.scrollToTop();
50248 * Scrolls the grid to the top
50250 scrollToTop : function(){
50252 this.scroller.dom.scrollTop = 0;
50258 * Gets a panel in the header of the grid that can be used for toolbars etc.
50259 * After modifying the contents of this panel a call to grid.autoSize() may be
50260 * required to register any changes in size.
50261 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
50262 * @return Roo.Element
50264 getHeaderPanel : function(doShow){
50266 this.headerPanel.show();
50268 return this.headerPanel;
50272 * Gets a panel in the footer of the grid that can be used for toolbars etc.
50273 * After modifying the contents of this panel a call to grid.autoSize() may be
50274 * required to register any changes in size.
50275 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
50276 * @return Roo.Element
50278 getFooterPanel : function(doShow){
50280 this.footerPanel.show();
50282 return this.footerPanel;
50285 initElements : function(){
50286 var E = Roo.Element;
50287 var el = this.grid.getGridEl().dom.firstChild;
50288 var cs = el.childNodes;
50290 this.el = new E(el);
50292 this.focusEl = new E(el.firstChild);
50293 this.focusEl.swallowEvent("click", true);
50295 this.headerPanel = new E(cs[1]);
50296 this.headerPanel.enableDisplayMode("block");
50298 this.scroller = new E(cs[2]);
50299 this.scrollSizer = new E(this.scroller.dom.firstChild);
50301 this.lockedWrap = new E(cs[3]);
50302 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
50303 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
50305 this.mainWrap = new E(cs[4]);
50306 this.mainHd = new E(this.mainWrap.dom.firstChild);
50307 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
50309 this.footerPanel = new E(cs[5]);
50310 this.footerPanel.enableDisplayMode("block");
50312 this.resizeProxy = new E(cs[6]);
50314 this.headerSelector = String.format(
50315 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
50316 this.lockedHd.id, this.mainHd.id
50319 this.splitterSelector = String.format(
50320 '#{0} div.x-grid-split, #{1} div.x-grid-split',
50321 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
50324 idToCssName : function(s)
50326 return s.replace(/[^a-z0-9]+/ig, '-');
50329 getHeaderCell : function(index){
50330 return Roo.DomQuery.select(this.headerSelector)[index];
50333 getHeaderCellMeasure : function(index){
50334 return this.getHeaderCell(index).firstChild;
50337 getHeaderCellText : function(index){
50338 return this.getHeaderCell(index).firstChild.firstChild;
50341 getLockedTable : function(){
50342 return this.lockedBody.dom.firstChild;
50345 getBodyTable : function(){
50346 return this.mainBody.dom.firstChild;
50349 getLockedRow : function(index){
50350 return this.getLockedTable().rows[index];
50353 getRow : function(index){
50354 return this.getBodyTable().rows[index];
50357 getRowComposite : function(index){
50359 this.rowEl = new Roo.CompositeElementLite();
50361 var els = [], lrow, mrow;
50362 if(lrow = this.getLockedRow(index)){
50365 if(mrow = this.getRow(index)){
50368 this.rowEl.elements = els;
50372 * Gets the 'td' of the cell
50374 * @param {Integer} rowIndex row to select
50375 * @param {Integer} colIndex column to select
50379 getCell : function(rowIndex, colIndex){
50380 var locked = this.cm.getLockedCount();
50382 if(colIndex < locked){
50383 source = this.lockedBody.dom.firstChild;
50385 source = this.mainBody.dom.firstChild;
50386 colIndex -= locked;
50388 return source.rows[rowIndex].childNodes[colIndex];
50391 getCellText : function(rowIndex, colIndex){
50392 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
50395 getCellBox : function(cell){
50396 var b = this.fly(cell).getBox();
50397 if(Roo.isOpera){ // opera fails to report the Y
50398 b.y = cell.offsetTop + this.mainBody.getY();
50403 getCellIndex : function(cell){
50404 var id = String(cell.className).match(this.cellRE);
50406 return parseInt(id[1], 10);
50411 findHeaderIndex : function(n){
50412 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
50413 return r ? this.getCellIndex(r) : false;
50416 findHeaderCell : function(n){
50417 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
50418 return r ? r : false;
50421 findRowIndex : function(n){
50425 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
50426 return r ? r.rowIndex : false;
50429 findCellIndex : function(node){
50430 var stop = this.el.dom;
50431 while(node && node != stop){
50432 if(this.findRE.test(node.className)){
50433 return this.getCellIndex(node);
50435 node = node.parentNode;
50440 getColumnId : function(index){
50441 return this.cm.getColumnId(index);
50444 getSplitters : function()
50446 if(this.splitterSelector){
50447 return Roo.DomQuery.select(this.splitterSelector);
50453 getSplitter : function(index){
50454 return this.getSplitters()[index];
50457 onRowOver : function(e, t){
50459 if((row = this.findRowIndex(t)) !== false){
50460 this.getRowComposite(row).addClass("x-grid-row-over");
50464 onRowOut : function(e, t){
50466 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
50467 this.getRowComposite(row).removeClass("x-grid-row-over");
50471 renderHeaders : function(){
50473 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
50474 var cb = [], lb = [], sb = [], lsb = [], p = {};
50475 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50476 p.cellId = "x-grid-hd-0-" + i;
50477 p.splitId = "x-grid-csplit-0-" + i;
50478 p.id = cm.getColumnId(i);
50479 p.title = cm.getColumnTooltip(i) || "";
50480 p.value = cm.getColumnHeader(i) || "";
50481 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
50482 if(!cm.isLocked(i)){
50483 cb[cb.length] = ct.apply(p);
50484 sb[sb.length] = st.apply(p);
50486 lb[lb.length] = ct.apply(p);
50487 lsb[lsb.length] = st.apply(p);
50490 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
50491 ht.apply({cells: cb.join(""), splits:sb.join("")})];
50494 updateHeaders : function(){
50495 var html = this.renderHeaders();
50496 this.lockedHd.update(html[0]);
50497 this.mainHd.update(html[1]);
50501 * Focuses the specified row.
50502 * @param {Number} row The row index
50504 focusRow : function(row)
50506 //Roo.log('GridView.focusRow');
50507 var x = this.scroller.dom.scrollLeft;
50508 this.focusCell(row, 0, false);
50509 this.scroller.dom.scrollLeft = x;
50513 * Focuses the specified cell.
50514 * @param {Number} row The row index
50515 * @param {Number} col The column index
50516 * @param {Boolean} hscroll false to disable horizontal scrolling
50518 focusCell : function(row, col, hscroll)
50520 //Roo.log('GridView.focusCell');
50521 var el = this.ensureVisible(row, col, hscroll);
50522 this.focusEl.alignTo(el, "tl-tl");
50524 this.focusEl.focus();
50526 this.focusEl.focus.defer(1, this.focusEl);
50531 * Scrolls the specified cell into view
50532 * @param {Number} row The row index
50533 * @param {Number} col The column index
50534 * @param {Boolean} hscroll false to disable horizontal scrolling
50536 ensureVisible : function(row, col, hscroll)
50538 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
50539 //return null; //disable for testing.
50540 if(typeof row != "number"){
50541 row = row.rowIndex;
50543 if(row < 0 && row >= this.ds.getCount()){
50546 col = (col !== undefined ? col : 0);
50547 var cm = this.grid.colModel;
50548 while(cm.isHidden(col)){
50552 var el = this.getCell(row, col);
50556 var c = this.scroller.dom;
50558 var ctop = parseInt(el.offsetTop, 10);
50559 var cleft = parseInt(el.offsetLeft, 10);
50560 var cbot = ctop + el.offsetHeight;
50561 var cright = cleft + el.offsetWidth;
50563 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
50564 var stop = parseInt(c.scrollTop, 10);
50565 var sleft = parseInt(c.scrollLeft, 10);
50566 var sbot = stop + ch;
50567 var sright = sleft + c.clientWidth;
50569 Roo.log('GridView.ensureVisible:' +
50571 ' c.clientHeight:' + c.clientHeight +
50572 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
50580 c.scrollTop = ctop;
50581 //Roo.log("set scrolltop to ctop DISABLE?");
50582 }else if(cbot > sbot){
50583 //Roo.log("set scrolltop to cbot-ch");
50584 c.scrollTop = cbot-ch;
50587 if(hscroll !== false){
50589 c.scrollLeft = cleft;
50590 }else if(cright > sright){
50591 c.scrollLeft = cright-c.clientWidth;
50598 updateColumns : function(){
50599 this.grid.stopEditing();
50600 var cm = this.grid.colModel, colIds = this.getColumnIds();
50601 //var totalWidth = cm.getTotalWidth();
50603 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50604 //if(cm.isHidden(i)) continue;
50605 var w = cm.getColumnWidth(i);
50606 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
50607 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
50609 this.updateSplitters();
50612 generateRules : function(cm){
50613 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
50614 Roo.util.CSS.removeStyleSheet(rulesId);
50615 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50616 var cid = cm.getColumnId(i);
50618 if(cm.config[i].align){
50619 align = 'text-align:'+cm.config[i].align+';';
50622 if(cm.isHidden(i)){
50623 hidden = 'display:none;';
50625 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
50627 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
50628 this.hdSelector, cid, " {\n", align, width, "}\n",
50629 this.tdSelector, cid, " {\n",hidden,"\n}\n",
50630 this.splitSelector, cid, " {\n", hidden , "\n}\n");
50632 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
50635 updateSplitters : function(){
50636 var cm = this.cm, s = this.getSplitters();
50637 if(s){ // splitters not created yet
50638 var pos = 0, locked = true;
50639 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50640 if(cm.isHidden(i)) continue;
50641 var w = cm.getColumnWidth(i); // make sure it's a number
50642 if(!cm.isLocked(i) && locked){
50647 s[i].style.left = (pos-this.splitOffset) + "px";
50652 handleHiddenChange : function(colModel, colIndex, hidden){
50654 this.hideColumn(colIndex);
50656 this.unhideColumn(colIndex);
50660 hideColumn : function(colIndex){
50661 var cid = this.getColumnId(colIndex);
50662 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
50663 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
50665 this.updateHeaders();
50667 this.updateSplitters();
50671 unhideColumn : function(colIndex){
50672 var cid = this.getColumnId(colIndex);
50673 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
50674 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
50677 this.updateHeaders();
50679 this.updateSplitters();
50683 insertRows : function(dm, firstRow, lastRow, isUpdate){
50684 if(firstRow == 0 && lastRow == dm.getCount()-1){
50688 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
50690 var s = this.getScrollState();
50691 var markup = this.renderRows(firstRow, lastRow);
50692 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
50693 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
50694 this.restoreScroll(s);
50696 this.fireEvent("rowsinserted", this, firstRow, lastRow);
50697 this.syncRowHeights(firstRow, lastRow);
50698 this.stripeRows(firstRow);
50704 bufferRows : function(markup, target, index){
50705 var before = null, trows = target.rows, tbody = target.tBodies[0];
50706 if(index < trows.length){
50707 before = trows[index];
50709 var b = document.createElement("div");
50710 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
50711 var rows = b.firstChild.rows;
50712 for(var i = 0, len = rows.length; i < len; i++){
50714 tbody.insertBefore(rows[0], before);
50716 tbody.appendChild(rows[0]);
50723 deleteRows : function(dm, firstRow, lastRow){
50724 if(dm.getRowCount()<1){
50725 this.fireEvent("beforerefresh", this);
50726 this.mainBody.update("");
50727 this.lockedBody.update("");
50728 this.fireEvent("refresh", this);
50730 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
50731 var bt = this.getBodyTable();
50732 var tbody = bt.firstChild;
50733 var rows = bt.rows;
50734 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
50735 tbody.removeChild(rows[firstRow]);
50737 this.stripeRows(firstRow);
50738 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
50742 updateRows : function(dataSource, firstRow, lastRow){
50743 var s = this.getScrollState();
50745 this.restoreScroll(s);
50748 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
50752 this.updateHeaderSortState();
50755 getScrollState : function(){
50757 var sb = this.scroller.dom;
50758 return {left: sb.scrollLeft, top: sb.scrollTop};
50761 stripeRows : function(startRow){
50762 if(!this.grid.stripeRows || this.ds.getCount() < 1){
50765 startRow = startRow || 0;
50766 var rows = this.getBodyTable().rows;
50767 var lrows = this.getLockedTable().rows;
50768 var cls = ' x-grid-row-alt ';
50769 for(var i = startRow, len = rows.length; i < len; i++){
50770 var row = rows[i], lrow = lrows[i];
50771 var isAlt = ((i+1) % 2 == 0);
50772 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
50773 if(isAlt == hasAlt){
50777 row.className += " x-grid-row-alt";
50779 row.className = row.className.replace("x-grid-row-alt", "");
50782 lrow.className = row.className;
50787 restoreScroll : function(state){
50788 //Roo.log('GridView.restoreScroll');
50789 var sb = this.scroller.dom;
50790 sb.scrollLeft = state.left;
50791 sb.scrollTop = state.top;
50795 syncScroll : function(){
50796 //Roo.log('GridView.syncScroll');
50797 var sb = this.scroller.dom;
50798 var sh = this.mainHd.dom;
50799 var bs = this.mainBody.dom;
50800 var lv = this.lockedBody.dom;
50801 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
50802 lv.scrollTop = bs.scrollTop = sb.scrollTop;
50805 handleScroll : function(e){
50807 var sb = this.scroller.dom;
50808 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
50812 handleWheel : function(e){
50813 var d = e.getWheelDelta();
50814 this.scroller.dom.scrollTop -= d*22;
50815 // set this here to prevent jumpy scrolling on large tables
50816 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
50820 renderRows : function(startRow, endRow){
50821 // pull in all the crap needed to render rows
50822 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
50823 var colCount = cm.getColumnCount();
50825 if(ds.getCount() < 1){
50829 // build a map for all the columns
50831 for(var i = 0; i < colCount; i++){
50832 var name = cm.getDataIndex(i);
50834 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
50835 renderer : cm.getRenderer(i),
50836 id : cm.getColumnId(i),
50837 locked : cm.isLocked(i)
50841 startRow = startRow || 0;
50842 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
50844 // records to render
50845 var rs = ds.getRange(startRow, endRow);
50847 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
50850 // As much as I hate to duplicate code, this was branched because FireFox really hates
50851 // [].join("") on strings. The performance difference was substantial enough to
50852 // branch this function
50853 doRender : Roo.isGecko ?
50854 function(cs, rs, ds, startRow, colCount, stripe){
50855 var ts = this.templates, ct = ts.cell, rt = ts.row;
50857 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
50859 var hasListener = this.grid.hasListener('rowclass');
50861 for(var j = 0, len = rs.length; j < len; j++){
50862 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
50863 for(var i = 0; i < colCount; i++){
50865 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
50867 p.css = p.attr = "";
50868 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
50869 if(p.value == undefined || p.value === "") p.value = " ";
50870 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
50871 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
50873 var markup = ct.apply(p);
50881 if(stripe && ((rowIndex+1) % 2 == 0)){
50882 alt.push("x-grid-row-alt")
50885 alt.push( " x-grid-dirty-row");
50888 if(this.getRowClass){
50889 alt.push(this.getRowClass(r, rowIndex));
50895 rowIndex : rowIndex,
50898 this.grid.fireEvent('rowclass', this, rowcfg);
50899 alt.push(rowcfg.rowClass);
50901 rp.alt = alt.join(" ");
50902 lbuf+= rt.apply(rp);
50904 buf+= rt.apply(rp);
50906 return [lbuf, buf];
50908 function(cs, rs, ds, startRow, colCount, stripe){
50909 var ts = this.templates, ct = ts.cell, rt = ts.row;
50911 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
50912 var hasListener = this.grid.hasListener('rowclass');
50915 for(var j = 0, len = rs.length; j < len; j++){
50916 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
50917 for(var i = 0; i < colCount; i++){
50919 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
50921 p.css = p.attr = "";
50922 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
50923 if(p.value == undefined || p.value === "") p.value = " ";
50924 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
50925 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
50928 var markup = ct.apply(p);
50930 cb[cb.length] = markup;
50932 lcb[lcb.length] = markup;
50936 if(stripe && ((rowIndex+1) % 2 == 0)){
50937 alt.push( "x-grid-row-alt");
50940 alt.push(" x-grid-dirty-row");
50943 if(this.getRowClass){
50944 alt.push( this.getRowClass(r, rowIndex));
50950 rowIndex : rowIndex,
50953 this.grid.fireEvent('rowclass', this, rowcfg);
50954 alt.push(rowcfg.rowClass);
50956 rp.alt = alt.join(" ");
50957 rp.cells = lcb.join("");
50958 lbuf[lbuf.length] = rt.apply(rp);
50959 rp.cells = cb.join("");
50960 buf[buf.length] = rt.apply(rp);
50962 return [lbuf.join(""), buf.join("")];
50965 renderBody : function(){
50966 var markup = this.renderRows();
50967 var bt = this.templates.body;
50968 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
50972 * Refreshes the grid
50973 * @param {Boolean} headersToo
50975 refresh : function(headersToo){
50976 this.fireEvent("beforerefresh", this);
50977 this.grid.stopEditing();
50978 var result = this.renderBody();
50979 this.lockedBody.update(result[0]);
50980 this.mainBody.update(result[1]);
50981 if(headersToo === true){
50982 this.updateHeaders();
50983 this.updateColumns();
50984 this.updateSplitters();
50985 this.updateHeaderSortState();
50987 this.syncRowHeights();
50989 this.fireEvent("refresh", this);
50992 handleColumnMove : function(cm, oldIndex, newIndex){
50993 this.indexMap = null;
50994 var s = this.getScrollState();
50995 this.refresh(true);
50996 this.restoreScroll(s);
50997 this.afterMove(newIndex);
51000 afterMove : function(colIndex){
51001 if(this.enableMoveAnim && Roo.enableFx){
51002 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
51004 // if multisort - fix sortOrder, and reload..
51005 if (this.grid.dataSource.multiSort) {
51006 // the we can call sort again..
51007 var dm = this.grid.dataSource;
51008 var cm = this.grid.colModel;
51010 for(var i = 0; i < cm.config.length; i++ ) {
51012 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
51013 continue; // dont' bother, it's not in sort list or being set.
51016 so.push(cm.config[i].dataIndex);
51019 dm.load(dm.lastOptions);
51026 updateCell : function(dm, rowIndex, dataIndex){
51027 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
51028 if(typeof colIndex == "undefined"){ // not present in grid
51031 var cm = this.grid.colModel;
51032 var cell = this.getCell(rowIndex, colIndex);
51033 var cellText = this.getCellText(rowIndex, colIndex);
51036 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
51037 id : cm.getColumnId(colIndex),
51038 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
51040 var renderer = cm.getRenderer(colIndex);
51041 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
51042 if(typeof val == "undefined" || val === "") val = " ";
51043 cellText.innerHTML = val;
51044 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
51045 this.syncRowHeights(rowIndex, rowIndex);
51048 calcColumnWidth : function(colIndex, maxRowsToMeasure){
51050 if(this.grid.autoSizeHeaders){
51051 var h = this.getHeaderCellMeasure(colIndex);
51052 maxWidth = Math.max(maxWidth, h.scrollWidth);
51055 if(this.cm.isLocked(colIndex)){
51056 tb = this.getLockedTable();
51059 tb = this.getBodyTable();
51060 index = colIndex - this.cm.getLockedCount();
51063 var rows = tb.rows;
51064 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
51065 for(var i = 0; i < stopIndex; i++){
51066 var cell = rows[i].childNodes[index].firstChild;
51067 maxWidth = Math.max(maxWidth, cell.scrollWidth);
51070 return maxWidth + /*margin for error in IE*/ 5;
51073 * Autofit a column to its content.
51074 * @param {Number} colIndex
51075 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
51077 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
51078 if(this.cm.isHidden(colIndex)){
51079 return; // can't calc a hidden column
51082 var cid = this.cm.getColumnId(colIndex);
51083 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
51084 if(this.grid.autoSizeHeaders){
51085 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
51088 var newWidth = this.calcColumnWidth(colIndex);
51089 this.cm.setColumnWidth(colIndex,
51090 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
51091 if(!suppressEvent){
51092 this.grid.fireEvent("columnresize", colIndex, newWidth);
51097 * Autofits all columns to their content and then expands to fit any extra space in the grid
51099 autoSizeColumns : function(){
51100 var cm = this.grid.colModel;
51101 var colCount = cm.getColumnCount();
51102 for(var i = 0; i < colCount; i++){
51103 this.autoSizeColumn(i, true, true);
51105 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
51108 this.updateColumns();
51114 * Autofits all columns to the grid's width proportionate with their current size
51115 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
51117 fitColumns : function(reserveScrollSpace){
51118 var cm = this.grid.colModel;
51119 var colCount = cm.getColumnCount();
51123 for (i = 0; i < colCount; i++){
51124 if(!cm.isHidden(i) && !cm.isFixed(i)){
51125 w = cm.getColumnWidth(i);
51131 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
51132 if(reserveScrollSpace){
51135 var frac = (avail - cm.getTotalWidth())/width;
51136 while (cols.length){
51139 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
51141 this.updateColumns();
51145 onRowSelect : function(rowIndex){
51146 var row = this.getRowComposite(rowIndex);
51147 row.addClass("x-grid-row-selected");
51150 onRowDeselect : function(rowIndex){
51151 var row = this.getRowComposite(rowIndex);
51152 row.removeClass("x-grid-row-selected");
51155 onCellSelect : function(row, col){
51156 var cell = this.getCell(row, col);
51158 Roo.fly(cell).addClass("x-grid-cell-selected");
51162 onCellDeselect : function(row, col){
51163 var cell = this.getCell(row, col);
51165 Roo.fly(cell).removeClass("x-grid-cell-selected");
51169 updateHeaderSortState : function(){
51171 // sort state can be single { field: xxx, direction : yyy}
51172 // or { xxx=>ASC , yyy : DESC ..... }
51175 if (!this.ds.multiSort) {
51176 var state = this.ds.getSortState();
51180 mstate[state.field] = state.direction;
51181 // FIXME... - this is not used here.. but might be elsewhere..
51182 this.sortState = state;
51185 mstate = this.ds.sortToggle;
51187 //remove existing sort classes..
51189 var sc = this.sortClasses;
51190 var hds = this.el.select(this.headerSelector).removeClass(sc);
51192 for(var f in mstate) {
51194 var sortColumn = this.cm.findColumnIndex(f);
51196 if(sortColumn != -1){
51197 var sortDir = mstate[f];
51198 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
51207 handleHeaderClick : function(g, index){
51208 if(this.headersDisabled){
51211 var dm = g.dataSource, cm = g.colModel;
51212 if(!cm.isSortable(index)){
51217 if (dm.multiSort) {
51218 // update the sortOrder
51220 for(var i = 0; i < cm.config.length; i++ ) {
51222 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
51223 continue; // dont' bother, it's not in sort list or being set.
51226 so.push(cm.config[i].dataIndex);
51232 dm.sort(cm.getDataIndex(index));
51236 destroy : function(){
51238 this.colMenu.removeAll();
51239 Roo.menu.MenuMgr.unregister(this.colMenu);
51240 this.colMenu.getEl().remove();
51241 delete this.colMenu;
51244 this.hmenu.removeAll();
51245 Roo.menu.MenuMgr.unregister(this.hmenu);
51246 this.hmenu.getEl().remove();
51249 if(this.grid.enableColumnMove){
51250 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
51252 for(var dd in dds){
51253 if(!dds[dd].config.isTarget && dds[dd].dragElId){
51254 var elid = dds[dd].dragElId;
51256 Roo.get(elid).remove();
51257 } else if(dds[dd].config.isTarget){
51258 dds[dd].proxyTop.remove();
51259 dds[dd].proxyBottom.remove();
51262 if(Roo.dd.DDM.locationCache[dd]){
51263 delete Roo.dd.DDM.locationCache[dd];
51266 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
51269 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
51270 this.bind(null, null);
51271 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
51274 handleLockChange : function(){
51275 this.refresh(true);
51278 onDenyColumnLock : function(){
51282 onDenyColumnHide : function(){
51286 handleHdMenuClick : function(item){
51287 var index = this.hdCtxIndex;
51288 var cm = this.cm, ds = this.ds;
51291 ds.sort(cm.getDataIndex(index), "ASC");
51294 ds.sort(cm.getDataIndex(index), "DESC");
51297 var lc = cm.getLockedCount();
51298 if(cm.getColumnCount(true) <= lc+1){
51299 this.onDenyColumnLock();
51303 cm.setLocked(index, true, true);
51304 cm.moveColumn(index, lc);
51305 this.grid.fireEvent("columnmove", index, lc);
51307 cm.setLocked(index, true);
51311 var lc = cm.getLockedCount();
51312 if((lc-1) != index){
51313 cm.setLocked(index, false, true);
51314 cm.moveColumn(index, lc-1);
51315 this.grid.fireEvent("columnmove", index, lc-1);
51317 cm.setLocked(index, false);
51321 index = cm.getIndexById(item.id.substr(4));
51323 if(item.checked && cm.getColumnCount(true) <= 1){
51324 this.onDenyColumnHide();
51327 cm.setHidden(index, item.checked);
51333 beforeColMenuShow : function(){
51334 var cm = this.cm, colCount = cm.getColumnCount();
51335 this.colMenu.removeAll();
51336 for(var i = 0; i < colCount; i++){
51337 this.colMenu.add(new Roo.menu.CheckItem({
51338 id: "col-"+cm.getColumnId(i),
51339 text: cm.getColumnHeader(i),
51340 checked: !cm.isHidden(i),
51346 handleHdCtx : function(g, index, e){
51348 var hd = this.getHeaderCell(index);
51349 this.hdCtxIndex = index;
51350 var ms = this.hmenu.items, cm = this.cm;
51351 ms.get("asc").setDisabled(!cm.isSortable(index));
51352 ms.get("desc").setDisabled(!cm.isSortable(index));
51353 if(this.grid.enableColLock !== false){
51354 ms.get("lock").setDisabled(cm.isLocked(index));
51355 ms.get("unlock").setDisabled(!cm.isLocked(index));
51357 this.hmenu.show(hd, "tl-bl");
51360 handleHdOver : function(e){
51361 var hd = this.findHeaderCell(e.getTarget());
51362 if(hd && !this.headersDisabled){
51363 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
51364 this.fly(hd).addClass("x-grid-hd-over");
51369 handleHdOut : function(e){
51370 var hd = this.findHeaderCell(e.getTarget());
51372 this.fly(hd).removeClass("x-grid-hd-over");
51376 handleSplitDblClick : function(e, t){
51377 var i = this.getCellIndex(t);
51378 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
51379 this.autoSizeColumn(i, true);
51384 render : function(){
51387 var colCount = cm.getColumnCount();
51389 if(this.grid.monitorWindowResize === true){
51390 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
51392 var header = this.renderHeaders();
51393 var body = this.templates.body.apply({rows:""});
51394 var html = this.templates.master.apply({
51397 lockedHeader: header[0],
51401 //this.updateColumns();
51403 this.grid.getGridEl().dom.innerHTML = html;
51405 this.initElements();
51407 // a kludge to fix the random scolling effect in webkit
51408 this.el.on("scroll", function() {
51409 this.el.dom.scrollTop=0; // hopefully not recursive..
51412 this.scroller.on("scroll", this.handleScroll, this);
51413 this.lockedBody.on("mousewheel", this.handleWheel, this);
51414 this.mainBody.on("mousewheel", this.handleWheel, this);
51416 this.mainHd.on("mouseover", this.handleHdOver, this);
51417 this.mainHd.on("mouseout", this.handleHdOut, this);
51418 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
51419 {delegate: "."+this.splitClass});
51421 this.lockedHd.on("mouseover", this.handleHdOver, this);
51422 this.lockedHd.on("mouseout", this.handleHdOut, this);
51423 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
51424 {delegate: "."+this.splitClass});
51426 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
51427 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51430 this.updateSplitters();
51432 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
51433 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51434 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51437 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
51438 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
51440 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
51441 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
51443 if(this.grid.enableColLock !== false){
51444 this.hmenu.add('-',
51445 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
51446 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
51449 if(this.grid.enableColumnHide !== false){
51451 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
51452 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
51453 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
51455 this.hmenu.add('-',
51456 {id:"columns", text: this.columnsText, menu: this.colMenu}
51459 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
51461 this.grid.on("headercontextmenu", this.handleHdCtx, this);
51464 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
51465 this.dd = new Roo.grid.GridDragZone(this.grid, {
51466 ddGroup : this.grid.ddGroup || 'GridDD'
51471 for(var i = 0; i < colCount; i++){
51472 if(cm.isHidden(i)){
51473 this.hideColumn(i);
51475 if(cm.config[i].align){
51476 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
51477 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
51481 this.updateHeaderSortState();
51483 this.beforeInitialResize();
51486 // two part rendering gives faster view to the user
51487 this.renderPhase2.defer(1, this);
51490 renderPhase2 : function(){
51491 // render the rows now
51493 if(this.grid.autoSizeColumns){
51494 this.autoSizeColumns();
51498 beforeInitialResize : function(){
51502 onColumnSplitterMoved : function(i, w){
51503 this.userResized = true;
51504 var cm = this.grid.colModel;
51505 cm.setColumnWidth(i, w, true);
51506 var cid = cm.getColumnId(i);
51507 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
51508 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
51509 this.updateSplitters();
51511 this.grid.fireEvent("columnresize", i, w);
51514 syncRowHeights : function(startIndex, endIndex){
51515 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
51516 startIndex = startIndex || 0;
51517 var mrows = this.getBodyTable().rows;
51518 var lrows = this.getLockedTable().rows;
51519 var len = mrows.length-1;
51520 endIndex = Math.min(endIndex || len, len);
51521 for(var i = startIndex; i <= endIndex; i++){
51522 var m = mrows[i], l = lrows[i];
51523 var h = Math.max(m.offsetHeight, l.offsetHeight);
51524 m.style.height = l.style.height = h + "px";
51529 layout : function(initialRender, is2ndPass){
51531 var auto = g.autoHeight;
51532 var scrollOffset = 16;
51533 var c = g.getGridEl(), cm = this.cm,
51534 expandCol = g.autoExpandColumn,
51536 //c.beginMeasure();
51538 if(!c.dom.offsetWidth){ // display:none?
51540 this.lockedWrap.show();
51541 this.mainWrap.show();
51546 var hasLock = this.cm.isLocked(0);
51548 var tbh = this.headerPanel.getHeight();
51549 var bbh = this.footerPanel.getHeight();
51552 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
51553 var newHeight = ch + c.getBorderWidth("tb");
51555 newHeight = Math.min(g.maxHeight, newHeight);
51557 c.setHeight(newHeight);
51561 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
51564 var s = this.scroller;
51566 var csize = c.getSize(true);
51568 this.el.setSize(csize.width, csize.height);
51570 this.headerPanel.setWidth(csize.width);
51571 this.footerPanel.setWidth(csize.width);
51573 var hdHeight = this.mainHd.getHeight();
51574 var vw = csize.width;
51575 var vh = csize.height - (tbh + bbh);
51579 var bt = this.getBodyTable();
51580 var ltWidth = hasLock ?
51581 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
51583 var scrollHeight = bt.offsetHeight;
51584 var scrollWidth = ltWidth + bt.offsetWidth;
51585 var vscroll = false, hscroll = false;
51587 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
51589 var lw = this.lockedWrap, mw = this.mainWrap;
51590 var lb = this.lockedBody, mb = this.mainBody;
51592 setTimeout(function(){
51593 var t = s.dom.offsetTop;
51594 var w = s.dom.clientWidth,
51595 h = s.dom.clientHeight;
51598 lw.setSize(ltWidth, h);
51600 mw.setLeftTop(ltWidth, t);
51601 mw.setSize(w-ltWidth, h);
51603 lb.setHeight(h-hdHeight);
51604 mb.setHeight(h-hdHeight);
51606 if(is2ndPass !== true && !gv.userResized && expandCol){
51607 // high speed resize without full column calculation
51609 var ci = cm.getIndexById(expandCol);
51611 ci = cm.findColumnIndex(expandCol);
51613 ci = Math.max(0, ci); // make sure it's got at least the first col.
51614 var expandId = cm.getColumnId(ci);
51615 var tw = cm.getTotalWidth(false);
51616 var currentWidth = cm.getColumnWidth(ci);
51617 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
51618 if(currentWidth != cw){
51619 cm.setColumnWidth(ci, cw, true);
51620 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
51621 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
51622 gv.updateSplitters();
51623 gv.layout(false, true);
51635 onWindowResize : function(){
51636 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
51642 appendFooter : function(parentEl){
51646 sortAscText : "Sort Ascending",
51647 sortDescText : "Sort Descending",
51648 lockText : "Lock Column",
51649 unlockText : "Unlock Column",
51650 columnsText : "Columns"
51654 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
51655 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
51656 this.proxy.el.addClass('x-grid3-col-dd');
51659 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
51660 handleMouseDown : function(e){
51664 callHandleMouseDown : function(e){
51665 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
51670 * Ext JS Library 1.1.1
51671 * Copyright(c) 2006-2007, Ext JS, LLC.
51673 * Originally Released Under LGPL - original licence link has changed is not relivant.
51676 * <script type="text/javascript">
51680 // This is a support class used internally by the Grid components
51681 Roo.grid.SplitDragZone = function(grid, hd, hd2){
51683 this.view = grid.getView();
51684 this.proxy = this.view.resizeProxy;
51685 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
51686 "gridSplitters" + this.grid.getGridEl().id, {
51687 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
51689 this.setHandleElId(Roo.id(hd));
51690 this.setOuterHandleElId(Roo.id(hd2));
51691 this.scroll = false;
51693 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
51694 fly: Roo.Element.fly,
51696 b4StartDrag : function(x, y){
51697 this.view.headersDisabled = true;
51698 this.proxy.setHeight(this.view.mainWrap.getHeight());
51699 var w = this.cm.getColumnWidth(this.cellIndex);
51700 var minw = Math.max(w-this.grid.minColumnWidth, 0);
51701 this.resetConstraints();
51702 this.setXConstraint(minw, 1000);
51703 this.setYConstraint(0, 0);
51704 this.minX = x - minw;
51705 this.maxX = x + 1000;
51707 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
51711 handleMouseDown : function(e){
51712 ev = Roo.EventObject.setEvent(e);
51713 var t = this.fly(ev.getTarget());
51714 if(t.hasClass("x-grid-split")){
51715 this.cellIndex = this.view.getCellIndex(t.dom);
51716 this.split = t.dom;
51717 this.cm = this.grid.colModel;
51718 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
51719 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
51724 endDrag : function(e){
51725 this.view.headersDisabled = false;
51726 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
51727 var diff = endX - this.startPos;
51728 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
51731 autoOffset : function(){
51732 this.setDelta(0,0);
51736 * Ext JS Library 1.1.1
51737 * Copyright(c) 2006-2007, Ext JS, LLC.
51739 * Originally Released Under LGPL - original licence link has changed is not relivant.
51742 * <script type="text/javascript">
51746 // This is a support class used internally by the Grid components
51747 Roo.grid.GridDragZone = function(grid, config){
51748 this.view = grid.getView();
51749 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
51750 if(this.view.lockedBody){
51751 this.setHandleElId(Roo.id(this.view.mainBody.dom));
51752 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
51754 this.scroll = false;
51756 this.ddel = document.createElement('div');
51757 this.ddel.className = 'x-grid-dd-wrap';
51760 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
51761 ddGroup : "GridDD",
51763 getDragData : function(e){
51764 var t = Roo.lib.Event.getTarget(e);
51765 var rowIndex = this.view.findRowIndex(t);
51766 if(rowIndex !== false){
51767 var sm = this.grid.selModel;
51768 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
51769 // sm.mouseDown(e, t);
51771 if (e.hasModifier()){
51772 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
51774 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
51779 onInitDrag : function(e){
51780 var data = this.dragData;
51781 this.ddel.innerHTML = this.grid.getDragDropText();
51782 this.proxy.update(this.ddel);
51783 // fire start drag?
51786 afterRepair : function(){
51787 this.dragging = false;
51790 getRepairXY : function(e, data){
51794 onEndDrag : function(data, e){
51798 onValidDrop : function(dd, e, id){
51803 beforeInvalidDrop : function(e, id){
51808 * Ext JS Library 1.1.1
51809 * Copyright(c) 2006-2007, Ext JS, LLC.
51811 * Originally Released Under LGPL - original licence link has changed is not relivant.
51814 * <script type="text/javascript">
51819 * @class Roo.grid.ColumnModel
51820 * @extends Roo.util.Observable
51821 * This is the default implementation of a ColumnModel used by the Grid. It defines
51822 * the columns in the grid.
51825 var colModel = new Roo.grid.ColumnModel([
51826 {header: "Ticker", width: 60, sortable: true, locked: true},
51827 {header: "Company Name", width: 150, sortable: true},
51828 {header: "Market Cap.", width: 100, sortable: true},
51829 {header: "$ Sales", width: 100, sortable: true, renderer: money},
51830 {header: "Employees", width: 100, sortable: true, resizable: false}
51835 * The config options listed for this class are options which may appear in each
51836 * individual column definition.
51837 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
51839 * @param {Object} config An Array of column config objects. See this class's
51840 * config objects for details.
51842 Roo.grid.ColumnModel = function(config){
51844 * The config passed into the constructor
51846 this.config = config;
51849 // if no id, create one
51850 // if the column does not have a dataIndex mapping,
51851 // map it to the order it is in the config
51852 for(var i = 0, len = config.length; i < len; i++){
51854 if(typeof c.dataIndex == "undefined"){
51857 if(typeof c.renderer == "string"){
51858 c.renderer = Roo.util.Format[c.renderer];
51860 if(typeof c.id == "undefined"){
51863 if(c.editor && c.editor.xtype){
51864 c.editor = Roo.factory(c.editor, Roo.grid);
51866 if(c.editor && c.editor.isFormField){
51867 c.editor = new Roo.grid.GridEditor(c.editor);
51869 this.lookup[c.id] = c;
51873 * The width of columns which have no width specified (defaults to 100)
51876 this.defaultWidth = 100;
51879 * Default sortable of columns which have no sortable specified (defaults to false)
51882 this.defaultSortable = false;
51886 * @event widthchange
51887 * Fires when the width of a column changes.
51888 * @param {ColumnModel} this
51889 * @param {Number} columnIndex The column index
51890 * @param {Number} newWidth The new width
51892 "widthchange": true,
51894 * @event headerchange
51895 * Fires when the text of a header changes.
51896 * @param {ColumnModel} this
51897 * @param {Number} columnIndex The column index
51898 * @param {Number} newText The new header text
51900 "headerchange": true,
51902 * @event hiddenchange
51903 * Fires when a column is hidden or "unhidden".
51904 * @param {ColumnModel} this
51905 * @param {Number} columnIndex The column index
51906 * @param {Boolean} hidden true if hidden, false otherwise
51908 "hiddenchange": true,
51910 * @event columnmoved
51911 * Fires when a column is moved.
51912 * @param {ColumnModel} this
51913 * @param {Number} oldIndex
51914 * @param {Number} newIndex
51916 "columnmoved" : true,
51918 * @event columlockchange
51919 * Fires when a column's locked state is changed
51920 * @param {ColumnModel} this
51921 * @param {Number} colIndex
51922 * @param {Boolean} locked true if locked
51924 "columnlockchange" : true
51926 Roo.grid.ColumnModel.superclass.constructor.call(this);
51928 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
51930 * @cfg {String} header The header text to display in the Grid view.
51933 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
51934 * {@link Roo.data.Record} definition from which to draw the column's value. If not
51935 * specified, the column's index is used as an index into the Record's data Array.
51938 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
51939 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
51942 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
51943 * Defaults to the value of the {@link #defaultSortable} property.
51944 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
51947 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
51950 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
51953 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
51956 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
51959 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
51960 * given the cell's data value. See {@link #setRenderer}. If not specified, the
51961 * default renderer uses the raw data value.
51964 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
51967 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
51971 * Returns the id of the column at the specified index.
51972 * @param {Number} index The column index
51973 * @return {String} the id
51975 getColumnId : function(index){
51976 return this.config[index].id;
51980 * Returns the column for a specified id.
51981 * @param {String} id The column id
51982 * @return {Object} the column
51984 getColumnById : function(id){
51985 return this.lookup[id];
51990 * Returns the column for a specified dataIndex.
51991 * @param {String} dataIndex The column dataIndex
51992 * @return {Object|Boolean} the column or false if not found
51994 getColumnByDataIndex: function(dataIndex){
51995 var index = this.findColumnIndex(dataIndex);
51996 return index > -1 ? this.config[index] : false;
52000 * Returns the index for a specified column id.
52001 * @param {String} id The column id
52002 * @return {Number} the index, or -1 if not found
52004 getIndexById : function(id){
52005 for(var i = 0, len = this.config.length; i < len; i++){
52006 if(this.config[i].id == id){
52014 * Returns the index for a specified column dataIndex.
52015 * @param {String} dataIndex The column dataIndex
52016 * @return {Number} the index, or -1 if not found
52019 findColumnIndex : function(dataIndex){
52020 for(var i = 0, len = this.config.length; i < len; i++){
52021 if(this.config[i].dataIndex == dataIndex){
52029 moveColumn : function(oldIndex, newIndex){
52030 var c = this.config[oldIndex];
52031 this.config.splice(oldIndex, 1);
52032 this.config.splice(newIndex, 0, c);
52033 this.dataMap = null;
52034 this.fireEvent("columnmoved", this, oldIndex, newIndex);
52037 isLocked : function(colIndex){
52038 return this.config[colIndex].locked === true;
52041 setLocked : function(colIndex, value, suppressEvent){
52042 if(this.isLocked(colIndex) == value){
52045 this.config[colIndex].locked = value;
52046 if(!suppressEvent){
52047 this.fireEvent("columnlockchange", this, colIndex, value);
52051 getTotalLockedWidth : function(){
52052 var totalWidth = 0;
52053 for(var i = 0; i < this.config.length; i++){
52054 if(this.isLocked(i) && !this.isHidden(i)){
52055 this.totalWidth += this.getColumnWidth(i);
52061 getLockedCount : function(){
52062 for(var i = 0, len = this.config.length; i < len; i++){
52063 if(!this.isLocked(i)){
52070 * Returns the number of columns.
52073 getColumnCount : function(visibleOnly){
52074 if(visibleOnly === true){
52076 for(var i = 0, len = this.config.length; i < len; i++){
52077 if(!this.isHidden(i)){
52083 return this.config.length;
52087 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
52088 * @param {Function} fn
52089 * @param {Object} scope (optional)
52090 * @return {Array} result
52092 getColumnsBy : function(fn, scope){
52094 for(var i = 0, len = this.config.length; i < len; i++){
52095 var c = this.config[i];
52096 if(fn.call(scope||this, c, i) === true){
52104 * Returns true if the specified column is sortable.
52105 * @param {Number} col The column index
52106 * @return {Boolean}
52108 isSortable : function(col){
52109 if(typeof this.config[col].sortable == "undefined"){
52110 return this.defaultSortable;
52112 return this.config[col].sortable;
52116 * Returns the rendering (formatting) function defined for the column.
52117 * @param {Number} col The column index.
52118 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
52120 getRenderer : function(col){
52121 if(!this.config[col].renderer){
52122 return Roo.grid.ColumnModel.defaultRenderer;
52124 return this.config[col].renderer;
52128 * Sets the rendering (formatting) function for a column.
52129 * @param {Number} col The column index
52130 * @param {Function} fn The function to use to process the cell's raw data
52131 * to return HTML markup for the grid view. The render function is called with
52132 * the following parameters:<ul>
52133 * <li>Data value.</li>
52134 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
52135 * <li>css A CSS style string to apply to the table cell.</li>
52136 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
52137 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
52138 * <li>Row index</li>
52139 * <li>Column index</li>
52140 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
52142 setRenderer : function(col, fn){
52143 this.config[col].renderer = fn;
52147 * Returns the width for the specified column.
52148 * @param {Number} col The column index
52151 getColumnWidth : function(col){
52152 return this.config[col].width * 1 || this.defaultWidth;
52156 * Sets the width for a column.
52157 * @param {Number} col The column index
52158 * @param {Number} width The new width
52160 setColumnWidth : function(col, width, suppressEvent){
52161 this.config[col].width = width;
52162 this.totalWidth = null;
52163 if(!suppressEvent){
52164 this.fireEvent("widthchange", this, col, width);
52169 * Returns the total width of all columns.
52170 * @param {Boolean} includeHidden True to include hidden column widths
52173 getTotalWidth : function(includeHidden){
52174 if(!this.totalWidth){
52175 this.totalWidth = 0;
52176 for(var i = 0, len = this.config.length; i < len; i++){
52177 if(includeHidden || !this.isHidden(i)){
52178 this.totalWidth += this.getColumnWidth(i);
52182 return this.totalWidth;
52186 * Returns the header for the specified column.
52187 * @param {Number} col The column index
52190 getColumnHeader : function(col){
52191 return this.config[col].header;
52195 * Sets the header for a column.
52196 * @param {Number} col The column index
52197 * @param {String} header The new header
52199 setColumnHeader : function(col, header){
52200 this.config[col].header = header;
52201 this.fireEvent("headerchange", this, col, header);
52205 * Returns the tooltip for the specified column.
52206 * @param {Number} col The column index
52209 getColumnTooltip : function(col){
52210 return this.config[col].tooltip;
52213 * Sets the tooltip for a column.
52214 * @param {Number} col The column index
52215 * @param {String} tooltip The new tooltip
52217 setColumnTooltip : function(col, tooltip){
52218 this.config[col].tooltip = tooltip;
52222 * Returns the dataIndex for the specified column.
52223 * @param {Number} col The column index
52226 getDataIndex : function(col){
52227 return this.config[col].dataIndex;
52231 * Sets the dataIndex for a column.
52232 * @param {Number} col The column index
52233 * @param {Number} dataIndex The new dataIndex
52235 setDataIndex : function(col, dataIndex){
52236 this.config[col].dataIndex = dataIndex;
52242 * Returns true if the cell is editable.
52243 * @param {Number} colIndex The column index
52244 * @param {Number} rowIndex The row index
52245 * @return {Boolean}
52247 isCellEditable : function(colIndex, rowIndex){
52248 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
52252 * Returns the editor defined for the cell/column.
52253 * return false or null to disable editing.
52254 * @param {Number} colIndex The column index
52255 * @param {Number} rowIndex The row index
52258 getCellEditor : function(colIndex, rowIndex){
52259 return this.config[colIndex].editor;
52263 * Sets if a column is editable.
52264 * @param {Number} col The column index
52265 * @param {Boolean} editable True if the column is editable
52267 setEditable : function(col, editable){
52268 this.config[col].editable = editable;
52273 * Returns true if the column is hidden.
52274 * @param {Number} colIndex The column index
52275 * @return {Boolean}
52277 isHidden : function(colIndex){
52278 return this.config[colIndex].hidden;
52283 * Returns true if the column width cannot be changed
52285 isFixed : function(colIndex){
52286 return this.config[colIndex].fixed;
52290 * Returns true if the column can be resized
52291 * @return {Boolean}
52293 isResizable : function(colIndex){
52294 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
52297 * Sets if a column is hidden.
52298 * @param {Number} colIndex The column index
52299 * @param {Boolean} hidden True if the column is hidden
52301 setHidden : function(colIndex, hidden){
52302 this.config[colIndex].hidden = hidden;
52303 this.totalWidth = null;
52304 this.fireEvent("hiddenchange", this, colIndex, hidden);
52308 * Sets the editor for a column.
52309 * @param {Number} col The column index
52310 * @param {Object} editor The editor object
52312 setEditor : function(col, editor){
52313 this.config[col].editor = editor;
52317 Roo.grid.ColumnModel.defaultRenderer = function(value){
52318 if(typeof value == "string" && value.length < 1){
52324 // Alias for backwards compatibility
52325 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
52328 * Ext JS Library 1.1.1
52329 * Copyright(c) 2006-2007, Ext JS, LLC.
52331 * Originally Released Under LGPL - original licence link has changed is not relivant.
52334 * <script type="text/javascript">
52338 * @class Roo.grid.AbstractSelectionModel
52339 * @extends Roo.util.Observable
52340 * Abstract base class for grid SelectionModels. It provides the interface that should be
52341 * implemented by descendant classes. This class should not be directly instantiated.
52344 Roo.grid.AbstractSelectionModel = function(){
52345 this.locked = false;
52346 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
52349 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
52350 /** @ignore Called by the grid automatically. Do not call directly. */
52351 init : function(grid){
52357 * Locks the selections.
52360 this.locked = true;
52364 * Unlocks the selections.
52366 unlock : function(){
52367 this.locked = false;
52371 * Returns true if the selections are locked.
52372 * @return {Boolean}
52374 isLocked : function(){
52375 return this.locked;
52379 * Ext JS Library 1.1.1
52380 * Copyright(c) 2006-2007, Ext JS, LLC.
52382 * Originally Released Under LGPL - original licence link has changed is not relivant.
52385 * <script type="text/javascript">
52388 * @extends Roo.grid.AbstractSelectionModel
52389 * @class Roo.grid.RowSelectionModel
52390 * The default SelectionModel used by {@link Roo.grid.Grid}.
52391 * It supports multiple selections and keyboard selection/navigation.
52393 * @param {Object} config
52395 Roo.grid.RowSelectionModel = function(config){
52396 Roo.apply(this, config);
52397 this.selections = new Roo.util.MixedCollection(false, function(o){
52402 this.lastActive = false;
52406 * @event selectionchange
52407 * Fires when the selection changes
52408 * @param {SelectionModel} this
52410 "selectionchange" : true,
52412 * @event afterselectionchange
52413 * Fires after the selection changes (eg. by key press or clicking)
52414 * @param {SelectionModel} this
52416 "afterselectionchange" : true,
52418 * @event beforerowselect
52419 * Fires when a row is selected being selected, return false to cancel.
52420 * @param {SelectionModel} this
52421 * @param {Number} rowIndex The selected index
52422 * @param {Boolean} keepExisting False if other selections will be cleared
52424 "beforerowselect" : true,
52427 * Fires when a row is selected.
52428 * @param {SelectionModel} this
52429 * @param {Number} rowIndex The selected index
52430 * @param {Roo.data.Record} r The record
52432 "rowselect" : true,
52434 * @event rowdeselect
52435 * Fires when a row is deselected.
52436 * @param {SelectionModel} this
52437 * @param {Number} rowIndex The selected index
52439 "rowdeselect" : true
52441 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
52442 this.locked = false;
52445 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
52447 * @cfg {Boolean} singleSelect
52448 * True to allow selection of only one row at a time (defaults to false)
52450 singleSelect : false,
52453 initEvents : function(){
52455 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
52456 this.grid.on("mousedown", this.handleMouseDown, this);
52457 }else{ // allow click to work like normal
52458 this.grid.on("rowclick", this.handleDragableRowClick, this);
52461 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
52462 "up" : function(e){
52464 this.selectPrevious(e.shiftKey);
52465 }else if(this.last !== false && this.lastActive !== false){
52466 var last = this.last;
52467 this.selectRange(this.last, this.lastActive-1);
52468 this.grid.getView().focusRow(this.lastActive);
52469 if(last !== false){
52473 this.selectFirstRow();
52475 this.fireEvent("afterselectionchange", this);
52477 "down" : function(e){
52479 this.selectNext(e.shiftKey);
52480 }else if(this.last !== false && this.lastActive !== false){
52481 var last = this.last;
52482 this.selectRange(this.last, this.lastActive+1);
52483 this.grid.getView().focusRow(this.lastActive);
52484 if(last !== false){
52488 this.selectFirstRow();
52490 this.fireEvent("afterselectionchange", this);
52495 var view = this.grid.view;
52496 view.on("refresh", this.onRefresh, this);
52497 view.on("rowupdated", this.onRowUpdated, this);
52498 view.on("rowremoved", this.onRemove, this);
52502 onRefresh : function(){
52503 var ds = this.grid.dataSource, i, v = this.grid.view;
52504 var s = this.selections;
52505 s.each(function(r){
52506 if((i = ds.indexOfId(r.id)) != -1){
52515 onRemove : function(v, index, r){
52516 this.selections.remove(r);
52520 onRowUpdated : function(v, index, r){
52521 if(this.isSelected(r)){
52522 v.onRowSelect(index);
52528 * @param {Array} records The records to select
52529 * @param {Boolean} keepExisting (optional) True to keep existing selections
52531 selectRecords : function(records, keepExisting){
52533 this.clearSelections();
52535 var ds = this.grid.dataSource;
52536 for(var i = 0, len = records.length; i < len; i++){
52537 this.selectRow(ds.indexOf(records[i]), true);
52542 * Gets the number of selected rows.
52545 getCount : function(){
52546 return this.selections.length;
52550 * Selects the first row in the grid.
52552 selectFirstRow : function(){
52557 * Select the last row.
52558 * @param {Boolean} keepExisting (optional) True to keep existing selections
52560 selectLastRow : function(keepExisting){
52561 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
52565 * Selects the row immediately following the last selected row.
52566 * @param {Boolean} keepExisting (optional) True to keep existing selections
52568 selectNext : function(keepExisting){
52569 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
52570 this.selectRow(this.last+1, keepExisting);
52571 this.grid.getView().focusRow(this.last);
52576 * Selects the row that precedes the last selected row.
52577 * @param {Boolean} keepExisting (optional) True to keep existing selections
52579 selectPrevious : function(keepExisting){
52581 this.selectRow(this.last-1, keepExisting);
52582 this.grid.getView().focusRow(this.last);
52587 * Returns the selected records
52588 * @return {Array} Array of selected records
52590 getSelections : function(){
52591 return [].concat(this.selections.items);
52595 * Returns the first selected record.
52598 getSelected : function(){
52599 return this.selections.itemAt(0);
52604 * Clears all selections.
52606 clearSelections : function(fast){
52607 if(this.locked) return;
52609 var ds = this.grid.dataSource;
52610 var s = this.selections;
52611 s.each(function(r){
52612 this.deselectRow(ds.indexOfId(r.id));
52616 this.selections.clear();
52623 * Selects all rows.
52625 selectAll : function(){
52626 if(this.locked) return;
52627 this.selections.clear();
52628 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
52629 this.selectRow(i, true);
52634 * Returns True if there is a selection.
52635 * @return {Boolean}
52637 hasSelection : function(){
52638 return this.selections.length > 0;
52642 * Returns True if the specified row is selected.
52643 * @param {Number/Record} record The record or index of the record to check
52644 * @return {Boolean}
52646 isSelected : function(index){
52647 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
52648 return (r && this.selections.key(r.id) ? true : false);
52652 * Returns True if the specified record id is selected.
52653 * @param {String} id The id of record to check
52654 * @return {Boolean}
52656 isIdSelected : function(id){
52657 return (this.selections.key(id) ? true : false);
52661 handleMouseDown : function(e, t){
52662 var view = this.grid.getView(), rowIndex;
52663 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
52666 if(e.shiftKey && this.last !== false){
52667 var last = this.last;
52668 this.selectRange(last, rowIndex, e.ctrlKey);
52669 this.last = last; // reset the last
52670 view.focusRow(rowIndex);
52672 var isSelected = this.isSelected(rowIndex);
52673 if(e.button !== 0 && isSelected){
52674 view.focusRow(rowIndex);
52675 }else if(e.ctrlKey && isSelected){
52676 this.deselectRow(rowIndex);
52677 }else if(!isSelected){
52678 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
52679 view.focusRow(rowIndex);
52682 this.fireEvent("afterselectionchange", this);
52685 handleDragableRowClick : function(grid, rowIndex, e)
52687 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
52688 this.selectRow(rowIndex, false);
52689 grid.view.focusRow(rowIndex);
52690 this.fireEvent("afterselectionchange", this);
52695 * Selects multiple rows.
52696 * @param {Array} rows Array of the indexes of the row to select
52697 * @param {Boolean} keepExisting (optional) True to keep existing selections
52699 selectRows : function(rows, keepExisting){
52701 this.clearSelections();
52703 for(var i = 0, len = rows.length; i < len; i++){
52704 this.selectRow(rows[i], true);
52709 * Selects a range of rows. All rows in between startRow and endRow are also selected.
52710 * @param {Number} startRow The index of the first row in the range
52711 * @param {Number} endRow The index of the last row in the range
52712 * @param {Boolean} keepExisting (optional) True to retain existing selections
52714 selectRange : function(startRow, endRow, keepExisting){
52715 if(this.locked) return;
52717 this.clearSelections();
52719 if(startRow <= endRow){
52720 for(var i = startRow; i <= endRow; i++){
52721 this.selectRow(i, true);
52724 for(var i = startRow; i >= endRow; i--){
52725 this.selectRow(i, true);
52731 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
52732 * @param {Number} startRow The index of the first row in the range
52733 * @param {Number} endRow The index of the last row in the range
52735 deselectRange : function(startRow, endRow, preventViewNotify){
52736 if(this.locked) return;
52737 for(var i = startRow; i <= endRow; i++){
52738 this.deselectRow(i, preventViewNotify);
52744 * @param {Number} row The index of the row to select
52745 * @param {Boolean} keepExisting (optional) True to keep existing selections
52747 selectRow : function(index, keepExisting, preventViewNotify){
52748 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
52749 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
52750 if(!keepExisting || this.singleSelect){
52751 this.clearSelections();
52753 var r = this.grid.dataSource.getAt(index);
52754 this.selections.add(r);
52755 this.last = this.lastActive = index;
52756 if(!preventViewNotify){
52757 this.grid.getView().onRowSelect(index);
52759 this.fireEvent("rowselect", this, index, r);
52760 this.fireEvent("selectionchange", this);
52766 * @param {Number} row The index of the row to deselect
52768 deselectRow : function(index, preventViewNotify){
52769 if(this.locked) return;
52770 if(this.last == index){
52773 if(this.lastActive == index){
52774 this.lastActive = false;
52776 var r = this.grid.dataSource.getAt(index);
52777 this.selections.remove(r);
52778 if(!preventViewNotify){
52779 this.grid.getView().onRowDeselect(index);
52781 this.fireEvent("rowdeselect", this, index);
52782 this.fireEvent("selectionchange", this);
52786 restoreLast : function(){
52788 this.last = this._last;
52793 acceptsNav : function(row, col, cm){
52794 return !cm.isHidden(col) && cm.isCellEditable(col, row);
52798 onEditorKey : function(field, e){
52799 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
52804 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
52806 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
52808 }else if(k == e.ENTER && !e.ctrlKey){
52812 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
52814 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
52816 }else if(k == e.ESC){
52820 g.startEditing(newCell[0], newCell[1]);
52825 * Ext JS Library 1.1.1
52826 * Copyright(c) 2006-2007, Ext JS, LLC.
52828 * Originally Released Under LGPL - original licence link has changed is not relivant.
52831 * <script type="text/javascript">
52834 * @class Roo.grid.CellSelectionModel
52835 * @extends Roo.grid.AbstractSelectionModel
52836 * This class provides the basic implementation for cell selection in a grid.
52838 * @param {Object} config The object containing the configuration of this model.
52839 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
52841 Roo.grid.CellSelectionModel = function(config){
52842 Roo.apply(this, config);
52844 this.selection = null;
52848 * @event beforerowselect
52849 * Fires before a cell is selected.
52850 * @param {SelectionModel} this
52851 * @param {Number} rowIndex The selected row index
52852 * @param {Number} colIndex The selected cell index
52854 "beforecellselect" : true,
52856 * @event cellselect
52857 * Fires when a cell is selected.
52858 * @param {SelectionModel} this
52859 * @param {Number} rowIndex The selected row index
52860 * @param {Number} colIndex The selected cell index
52862 "cellselect" : true,
52864 * @event selectionchange
52865 * Fires when the active selection changes.
52866 * @param {SelectionModel} this
52867 * @param {Object} selection null for no selection or an object (o) with two properties
52869 <li>o.record: the record object for the row the selection is in</li>
52870 <li>o.cell: An array of [rowIndex, columnIndex]</li>
52873 "selectionchange" : true,
52876 * Fires when the tab (or enter) was pressed on the last editable cell
52877 * You can use this to trigger add new row.
52878 * @param {SelectionModel} this
52882 * @event beforeeditnext
52883 * Fires before the next editable sell is made active
52884 * You can use this to skip to another cell or fire the tabend
52885 * if you set cell to false
52886 * @param {Object} eventdata object : { cell : [ row, col ] }
52888 "beforeeditnext" : true
52890 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
52893 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
52895 enter_is_tab: false,
52898 initEvents : function(){
52899 this.grid.on("mousedown", this.handleMouseDown, this);
52900 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
52901 var view = this.grid.view;
52902 view.on("refresh", this.onViewChange, this);
52903 view.on("rowupdated", this.onRowUpdated, this);
52904 view.on("beforerowremoved", this.clearSelections, this);
52905 view.on("beforerowsinserted", this.clearSelections, this);
52906 if(this.grid.isEditor){
52907 this.grid.on("beforeedit", this.beforeEdit, this);
52912 beforeEdit : function(e){
52913 this.select(e.row, e.column, false, true, e.record);
52917 onRowUpdated : function(v, index, r){
52918 if(this.selection && this.selection.record == r){
52919 v.onCellSelect(index, this.selection.cell[1]);
52924 onViewChange : function(){
52925 this.clearSelections(true);
52929 * Returns the currently selected cell,.
52930 * @return {Array} The selected cell (row, column) or null if none selected.
52932 getSelectedCell : function(){
52933 return this.selection ? this.selection.cell : null;
52937 * Clears all selections.
52938 * @param {Boolean} true to prevent the gridview from being notified about the change.
52940 clearSelections : function(preventNotify){
52941 var s = this.selection;
52943 if(preventNotify !== true){
52944 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
52946 this.selection = null;
52947 this.fireEvent("selectionchange", this, null);
52952 * Returns true if there is a selection.
52953 * @return {Boolean}
52955 hasSelection : function(){
52956 return this.selection ? true : false;
52960 handleMouseDown : function(e, t){
52961 var v = this.grid.getView();
52962 if(this.isLocked()){
52965 var row = v.findRowIndex(t);
52966 var cell = v.findCellIndex(t);
52967 if(row !== false && cell !== false){
52968 this.select(row, cell);
52974 * @param {Number} rowIndex
52975 * @param {Number} collIndex
52977 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
52978 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
52979 this.clearSelections();
52980 r = r || this.grid.dataSource.getAt(rowIndex);
52983 cell : [rowIndex, colIndex]
52985 if(!preventViewNotify){
52986 var v = this.grid.getView();
52987 v.onCellSelect(rowIndex, colIndex);
52988 if(preventFocus !== true){
52989 v.focusCell(rowIndex, colIndex);
52992 this.fireEvent("cellselect", this, rowIndex, colIndex);
52993 this.fireEvent("selectionchange", this, this.selection);
52998 isSelectable : function(rowIndex, colIndex, cm){
52999 return !cm.isHidden(colIndex);
53003 handleKeyDown : function(e){
53004 //Roo.log('Cell Sel Model handleKeyDown');
53005 if(!e.isNavKeyPress()){
53008 var g = this.grid, s = this.selection;
53011 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
53013 this.select(cell[0], cell[1]);
53018 var walk = function(row, col, step){
53019 return g.walkCells(row, col, step, sm.isSelectable, sm);
53021 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
53028 // handled by onEditorKey
53029 if (g.isEditor && g.editing) {
53033 newCell = walk(r, c-1, -1);
53035 newCell = walk(r, c+1, 1);
53040 newCell = walk(r+1, c, 1);
53044 newCell = walk(r-1, c, -1);
53048 newCell = walk(r, c+1, 1);
53052 newCell = walk(r, c-1, -1);
53057 if(g.isEditor && !g.editing){
53058 g.startEditing(r, c);
53067 this.select(newCell[0], newCell[1]);
53073 acceptsNav : function(row, col, cm){
53074 return !cm.isHidden(col) && cm.isCellEditable(col, row);
53078 * @param {Number} field (not used) - as it's normally used as a listener
53079 * @param {Number} e - event - fake it by using
53081 * var e = Roo.EventObjectImpl.prototype;
53082 * e.keyCode = e.TAB
53086 onEditorKey : function(field, e){
53088 var k = e.getKey(),
53091 ed = g.activeEditor,
53093 ///Roo.log('onEditorKey' + k);
53096 if (this.enter_is_tab && k == e.ENTER) {
53102 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
53104 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53110 } else if(k == e.ENTER && !e.ctrlKey){
53113 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53115 } else if(k == e.ESC){
53120 var ecall = { cell : newCell, forward : forward };
53121 this.fireEvent('beforeeditnext', ecall );
53122 newCell = ecall.cell;
53123 forward = ecall.forward;
53127 //Roo.log('next cell after edit');
53128 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
53129 } else if (forward) {
53130 // tabbed past last
53131 this.fireEvent.defer(100, this, ['tabend',this]);
53136 * Ext JS Library 1.1.1
53137 * Copyright(c) 2006-2007, Ext JS, LLC.
53139 * Originally Released Under LGPL - original licence link has changed is not relivant.
53142 * <script type="text/javascript">
53146 * @class Roo.grid.EditorGrid
53147 * @extends Roo.grid.Grid
53148 * Class for creating and editable grid.
53149 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53150 * The container MUST have some type of size defined for the grid to fill. The container will be
53151 * automatically set to position relative if it isn't already.
53152 * @param {Object} dataSource The data model to bind to
53153 * @param {Object} colModel The column model with info about this grid's columns
53155 Roo.grid.EditorGrid = function(container, config){
53156 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
53157 this.getGridEl().addClass("xedit-grid");
53159 if(!this.selModel){
53160 this.selModel = new Roo.grid.CellSelectionModel();
53163 this.activeEditor = null;
53167 * @event beforeedit
53168 * Fires before cell editing is triggered. The edit event object has the following properties <br />
53169 * <ul style="padding:5px;padding-left:16px;">
53170 * <li>grid - This grid</li>
53171 * <li>record - The record being edited</li>
53172 * <li>field - The field name being edited</li>
53173 * <li>value - The value for the field being edited.</li>
53174 * <li>row - The grid row index</li>
53175 * <li>column - The grid column index</li>
53176 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
53178 * @param {Object} e An edit event (see above for description)
53180 "beforeedit" : true,
53183 * Fires after a cell is edited. <br />
53184 * <ul style="padding:5px;padding-left:16px;">
53185 * <li>grid - This grid</li>
53186 * <li>record - The record being edited</li>
53187 * <li>field - The field name being edited</li>
53188 * <li>value - The value being set</li>
53189 * <li>originalValue - The original value for the field, before the edit.</li>
53190 * <li>row - The grid row index</li>
53191 * <li>column - The grid column index</li>
53193 * @param {Object} e An edit event (see above for description)
53195 "afteredit" : true,
53197 * @event validateedit
53198 * Fires after a cell is edited, but before the value is set in the record.
53199 * You can use this to modify the value being set in the field, Return false
53200 * to cancel the change. The edit event object has the following properties <br />
53201 * <ul style="padding:5px;padding-left:16px;">
53202 * <li>editor - This editor</li>
53203 * <li>grid - This grid</li>
53204 * <li>record - The record being edited</li>
53205 * <li>field - The field name being edited</li>
53206 * <li>value - The value being set</li>
53207 * <li>originalValue - The original value for the field, before the edit.</li>
53208 * <li>row - The grid row index</li>
53209 * <li>column - The grid column index</li>
53210 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
53212 * @param {Object} e An edit event (see above for description)
53214 "validateedit" : true
53216 this.on("bodyscroll", this.stopEditing, this);
53217 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
53220 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
53222 * @cfg {Number} clicksToEdit
53223 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
53230 trackMouseOver: false, // causes very odd FF errors
53232 onCellDblClick : function(g, row, col){
53233 this.startEditing(row, col);
53236 onEditComplete : function(ed, value, startValue){
53237 this.editing = false;
53238 this.activeEditor = null;
53239 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
53241 var field = this.colModel.getDataIndex(ed.col);
53246 originalValue: startValue,
53253 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
53256 if(String(value) !== String(startValue)){
53258 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
53259 r.set(field, e.value);
53260 // if we are dealing with a combo box..
53261 // then we also set the 'name' colum to be the displayField
53262 if (ed.field.displayField && ed.field.name) {
53263 r.set(ed.field.name, ed.field.el.dom.value);
53266 delete e.cancel; //?? why!!!
53267 this.fireEvent("afteredit", e);
53270 this.fireEvent("afteredit", e); // always fire it!
53272 this.view.focusCell(ed.row, ed.col);
53276 * Starts editing the specified for the specified row/column
53277 * @param {Number} rowIndex
53278 * @param {Number} colIndex
53280 startEditing : function(row, col){
53281 this.stopEditing();
53282 if(this.colModel.isCellEditable(col, row)){
53283 this.view.ensureVisible(row, col, true);
53285 var r = this.dataSource.getAt(row);
53286 var field = this.colModel.getDataIndex(col);
53287 var cell = Roo.get(this.view.getCell(row,col));
53292 value: r.data[field],
53297 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
53298 this.editing = true;
53299 var ed = this.colModel.getCellEditor(col, row);
53305 ed.render(ed.parentEl || document.body);
53311 (function(){ // complex but required for focus issues in safari, ie and opera
53315 ed.on("complete", this.onEditComplete, this, {single: true});
53316 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
53317 this.activeEditor = ed;
53318 var v = r.data[field];
53319 ed.startEdit(this.view.getCell(row, col), v);
53320 // combo's with 'displayField and name set
53321 if (ed.field.displayField && ed.field.name) {
53322 ed.field.el.dom.value = r.data[ed.field.name];
53326 }).defer(50, this);
53332 * Stops any active editing
53334 stopEditing : function(){
53335 if(this.activeEditor){
53336 this.activeEditor.completeEdit();
53338 this.activeEditor = null;
53342 * Ext JS Library 1.1.1
53343 * Copyright(c) 2006-2007, Ext JS, LLC.
53345 * Originally Released Under LGPL - original licence link has changed is not relivant.
53348 * <script type="text/javascript">
53351 // private - not really -- you end up using it !
53352 // This is a support class used internally by the Grid components
53355 * @class Roo.grid.GridEditor
53356 * @extends Roo.Editor
53357 * Class for creating and editable grid elements.
53358 * @param {Object} config any settings (must include field)
53360 Roo.grid.GridEditor = function(field, config){
53361 if (!config && field.field) {
53363 field = Roo.factory(config.field, Roo.form);
53365 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
53366 field.monitorTab = false;
53369 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
53372 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
53375 alignment: "tl-tl",
53378 cls: "x-small-editor x-grid-editor",
53383 * Ext JS Library 1.1.1
53384 * Copyright(c) 2006-2007, Ext JS, LLC.
53386 * Originally Released Under LGPL - original licence link has changed is not relivant.
53389 * <script type="text/javascript">
53394 Roo.grid.PropertyRecord = Roo.data.Record.create([
53395 {name:'name',type:'string'}, 'value'
53399 Roo.grid.PropertyStore = function(grid, source){
53401 this.store = new Roo.data.Store({
53402 recordType : Roo.grid.PropertyRecord
53404 this.store.on('update', this.onUpdate, this);
53406 this.setSource(source);
53408 Roo.grid.PropertyStore.superclass.constructor.call(this);
53413 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
53414 setSource : function(o){
53416 this.store.removeAll();
53419 if(this.isEditableValue(o[k])){
53420 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
53423 this.store.loadRecords({records: data}, {}, true);
53426 onUpdate : function(ds, record, type){
53427 if(type == Roo.data.Record.EDIT){
53428 var v = record.data['value'];
53429 var oldValue = record.modified['value'];
53430 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
53431 this.source[record.id] = v;
53433 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
53440 getProperty : function(row){
53441 return this.store.getAt(row);
53444 isEditableValue: function(val){
53445 if(val && val instanceof Date){
53447 }else if(typeof val == 'object' || typeof val == 'function'){
53453 setValue : function(prop, value){
53454 this.source[prop] = value;
53455 this.store.getById(prop).set('value', value);
53458 getSource : function(){
53459 return this.source;
53463 Roo.grid.PropertyColumnModel = function(grid, store){
53466 g.PropertyColumnModel.superclass.constructor.call(this, [
53467 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
53468 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
53470 this.store = store;
53471 this.bselect = Roo.DomHelper.append(document.body, {
53472 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
53473 {tag: 'option', value: 'true', html: 'true'},
53474 {tag: 'option', value: 'false', html: 'false'}
53477 Roo.id(this.bselect);
53480 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
53481 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
53482 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
53483 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
53484 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
53486 this.renderCellDelegate = this.renderCell.createDelegate(this);
53487 this.renderPropDelegate = this.renderProp.createDelegate(this);
53490 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
53494 valueText : 'Value',
53496 dateFormat : 'm/j/Y',
53499 renderDate : function(dateVal){
53500 return dateVal.dateFormat(this.dateFormat);
53503 renderBool : function(bVal){
53504 return bVal ? 'true' : 'false';
53507 isCellEditable : function(colIndex, rowIndex){
53508 return colIndex == 1;
53511 getRenderer : function(col){
53513 this.renderCellDelegate : this.renderPropDelegate;
53516 renderProp : function(v){
53517 return this.getPropertyName(v);
53520 renderCell : function(val){
53522 if(val instanceof Date){
53523 rv = this.renderDate(val);
53524 }else if(typeof val == 'boolean'){
53525 rv = this.renderBool(val);
53527 return Roo.util.Format.htmlEncode(rv);
53530 getPropertyName : function(name){
53531 var pn = this.grid.propertyNames;
53532 return pn && pn[name] ? pn[name] : name;
53535 getCellEditor : function(colIndex, rowIndex){
53536 var p = this.store.getProperty(rowIndex);
53537 var n = p.data['name'], val = p.data['value'];
53539 if(typeof(this.grid.customEditors[n]) == 'string'){
53540 return this.editors[this.grid.customEditors[n]];
53542 if(typeof(this.grid.customEditors[n]) != 'undefined'){
53543 return this.grid.customEditors[n];
53545 if(val instanceof Date){
53546 return this.editors['date'];
53547 }else if(typeof val == 'number'){
53548 return this.editors['number'];
53549 }else if(typeof val == 'boolean'){
53550 return this.editors['boolean'];
53552 return this.editors['string'];
53558 * @class Roo.grid.PropertyGrid
53559 * @extends Roo.grid.EditorGrid
53560 * This class represents the interface of a component based property grid control.
53561 * <br><br>Usage:<pre><code>
53562 var grid = new Roo.grid.PropertyGrid("my-container-id", {
53570 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53571 * The container MUST have some type of size defined for the grid to fill. The container will be
53572 * automatically set to position relative if it isn't already.
53573 * @param {Object} config A config object that sets properties on this grid.
53575 Roo.grid.PropertyGrid = function(container, config){
53576 config = config || {};
53577 var store = new Roo.grid.PropertyStore(this);
53578 this.store = store;
53579 var cm = new Roo.grid.PropertyColumnModel(this, store);
53580 store.store.sort('name', 'ASC');
53581 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
53584 enableColLock:false,
53585 enableColumnMove:false,
53587 trackMouseOver: false,
53590 this.getGridEl().addClass('x-props-grid');
53591 this.lastEditRow = null;
53592 this.on('columnresize', this.onColumnResize, this);
53595 * @event beforepropertychange
53596 * Fires before a property changes (return false to stop?)
53597 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
53598 * @param {String} id Record Id
53599 * @param {String} newval New Value
53600 * @param {String} oldval Old Value
53602 "beforepropertychange": true,
53604 * @event propertychange
53605 * Fires after a property changes
53606 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
53607 * @param {String} id Record Id
53608 * @param {String} newval New Value
53609 * @param {String} oldval Old Value
53611 "propertychange": true
53613 this.customEditors = this.customEditors || {};
53615 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
53618 * @cfg {Object} customEditors map of colnames=> custom editors.
53619 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
53620 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
53621 * false disables editing of the field.
53625 * @cfg {Object} propertyNames map of property Names to their displayed value
53628 render : function(){
53629 Roo.grid.PropertyGrid.superclass.render.call(this);
53630 this.autoSize.defer(100, this);
53633 autoSize : function(){
53634 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
53636 this.view.fitColumns();
53640 onColumnResize : function(){
53641 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
53645 * Sets the data for the Grid
53646 * accepts a Key => Value object of all the elements avaiable.
53647 * @param {Object} data to appear in grid.
53649 setSource : function(source){
53650 this.store.setSource(source);
53654 * Gets all the data from the grid.
53655 * @return {Object} data data stored in grid
53657 getSource : function(){
53658 return this.store.getSource();
53662 * Ext JS Library 1.1.1
53663 * Copyright(c) 2006-2007, Ext JS, LLC.
53665 * Originally Released Under LGPL - original licence link has changed is not relivant.
53668 * <script type="text/javascript">
53672 * @class Roo.LoadMask
53673 * A simple utility class for generically masking elements while loading data. If the element being masked has
53674 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
53675 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
53676 * element's UpdateManager load indicator and will be destroyed after the initial load.
53678 * Create a new LoadMask
53679 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
53680 * @param {Object} config The config object
53682 Roo.LoadMask = function(el, config){
53683 this.el = Roo.get(el);
53684 Roo.apply(this, config);
53686 this.store.on('beforeload', this.onBeforeLoad, this);
53687 this.store.on('load', this.onLoad, this);
53688 this.store.on('loadexception', this.onLoadException, this);
53689 this.removeMask = false;
53691 var um = this.el.getUpdateManager();
53692 um.showLoadIndicator = false; // disable the default indicator
53693 um.on('beforeupdate', this.onBeforeLoad, this);
53694 um.on('update', this.onLoad, this);
53695 um.on('failure', this.onLoad, this);
53696 this.removeMask = true;
53700 Roo.LoadMask.prototype = {
53702 * @cfg {Boolean} removeMask
53703 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
53704 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
53707 * @cfg {String} msg
53708 * The text to display in a centered loading message box (defaults to 'Loading...')
53710 msg : 'Loading...',
53712 * @cfg {String} msgCls
53713 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
53715 msgCls : 'x-mask-loading',
53718 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
53724 * Disables the mask to prevent it from being displayed
53726 disable : function(){
53727 this.disabled = true;
53731 * Enables the mask so that it can be displayed
53733 enable : function(){
53734 this.disabled = false;
53737 onLoadException : function()
53739 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
53740 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
53742 this.el.unmask(this.removeMask);
53745 onLoad : function()
53747 this.el.unmask(this.removeMask);
53751 onBeforeLoad : function(){
53752 if(!this.disabled){
53753 this.el.mask(this.msg, this.msgCls);
53758 destroy : function(){
53760 this.store.un('beforeload', this.onBeforeLoad, this);
53761 this.store.un('load', this.onLoad, this);
53762 this.store.un('loadexception', this.onLoadException, this);
53764 var um = this.el.getUpdateManager();
53765 um.un('beforeupdate', this.onBeforeLoad, this);
53766 um.un('update', this.onLoad, this);
53767 um.un('failure', this.onLoad, this);
53772 * Ext JS Library 1.1.1
53773 * Copyright(c) 2006-2007, Ext JS, LLC.
53775 * Originally Released Under LGPL - original licence link has changed is not relivant.
53778 * <script type="text/javascript">
53783 * @class Roo.XTemplate
53784 * @extends Roo.Template
53785 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
53787 var t = new Roo.XTemplate(
53788 '<select name="{name}">',
53789 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
53793 // then append, applying the master template values
53796 * Supported features:
53801 {a_variable} - output encoded.
53802 {a_variable.format:("Y-m-d")} - call a method on the variable
53803 {a_variable:raw} - unencoded output
53804 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
53805 {a_variable:this.method_on_template(...)} - call a method on the template object.
53810 <tpl for="a_variable or condition.."></tpl>
53811 <tpl if="a_variable or condition"></tpl>
53812 <tpl exec="some javascript"></tpl>
53813 <tpl name="named_template"></tpl> (experimental)
53815 <tpl for="."></tpl> - just iterate the property..
53816 <tpl for=".."></tpl> - iterates with the parent (probably the template)
53820 Roo.XTemplate = function()
53822 Roo.XTemplate.superclass.constructor.apply(this, arguments);
53829 Roo.extend(Roo.XTemplate, Roo.Template, {
53832 * The various sub templates
53837 * basic tag replacing syntax
53840 * // you can fake an object call by doing this
53844 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
53847 * compile the template
53849 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
53852 compile: function()
53856 s = ['<tpl>', s, '</tpl>'].join('');
53858 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
53859 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
53860 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
53861 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
53862 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
53867 while(true == !!(m = s.match(re))){
53868 var forMatch = m[0].match(nameRe),
53869 ifMatch = m[0].match(ifRe),
53870 execMatch = m[0].match(execRe),
53871 namedMatch = m[0].match(namedRe),
53876 name = forMatch && forMatch[1] ? forMatch[1] : '';
53879 // if - puts fn into test..
53880 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
53882 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
53887 // exec - calls a function... returns empty if true is returned.
53888 exp = execMatch && execMatch[1] ? execMatch[1] : null;
53890 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
53898 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
53899 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
53900 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
53903 var uid = namedMatch ? namedMatch[1] : id;
53907 id: namedMatch ? namedMatch[1] : id,
53914 s = s.replace(m[0], '');
53916 s = s.replace(m[0], '{xtpl'+ id + '}');
53921 for(var i = tpls.length-1; i >= 0; --i){
53922 this.compileTpl(tpls[i]);
53923 this.tpls[tpls[i].id] = tpls[i];
53925 this.master = tpls[tpls.length-1];
53929 * same as applyTemplate, except it's done to one of the subTemplates
53930 * when using named templates, you can do:
53932 * var str = pl.applySubTemplate('your-name', values);
53935 * @param {Number} id of the template
53936 * @param {Object} values to apply to template
53937 * @param {Object} parent (normaly the instance of this object)
53939 applySubTemplate : function(id, values, parent)
53943 var t = this.tpls[id];
53947 if(t.test && !t.test.call(this, values, parent)){
53951 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
53952 Roo.log(e.toString());
53958 if(t.exec && t.exec.call(this, values, parent)){
53962 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
53963 Roo.log(e.toString());
53968 var vs = t.target ? t.target.call(this, values, parent) : values;
53969 parent = t.target ? values : parent;
53970 if(t.target && vs instanceof Array){
53972 for(var i = 0, len = vs.length; i < len; i++){
53973 buf[buf.length] = t.compiled.call(this, vs[i], parent);
53975 return buf.join('');
53977 return t.compiled.call(this, vs, parent);
53979 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
53980 Roo.log(e.toString());
53981 Roo.log(t.compiled);
53986 compileTpl : function(tpl)
53988 var fm = Roo.util.Format;
53989 var useF = this.disableFormats !== true;
53990 var sep = Roo.isGecko ? "+" : ",";
53991 var undef = function(str) {
53992 Roo.log("Property not found :" + str);
53996 var fn = function(m, name, format, args)
53998 //Roo.log(arguments);
53999 args = args ? args.replace(/\\'/g,"'") : args;
54000 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
54001 if (typeof(format) == 'undefined') {
54002 format= 'htmlEncode';
54004 if (format == 'raw' ) {
54008 if(name.substr(0, 4) == 'xtpl'){
54009 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
54012 // build an array of options to determine if value is undefined..
54014 // basically get 'xxxx.yyyy' then do
54015 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
54016 // (function () { Roo.log("Property not found"); return ''; })() :
54021 Roo.each(name.split('.'), function(st) {
54022 lookfor += (lookfor.length ? '.': '') + st;
54023 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
54026 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
54029 if(format && useF){
54031 args = args ? ',' + args : "";
54033 if(format.substr(0, 5) != "this."){
54034 format = "fm." + format + '(';
54036 format = 'this.call("'+ format.substr(5) + '", ';
54040 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
54044 // called with xxyx.yuu:(test,test)
54046 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
54048 // raw.. - :raw modifier..
54049 return "'"+ sep + udef_st + name + ")"+sep+"'";
54053 // branched to use + in gecko and [].join() in others
54055 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
54056 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
54059 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
54060 body.push(tpl.body.replace(/(\r\n|\n)/g,
54061 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
54062 body.push("'].join('');};};");
54063 body = body.join('');
54066 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
54068 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
54074 applyTemplate : function(values){
54075 return this.master.compiled.call(this, values, {});
54076 //var s = this.subs;
54079 apply : function(){
54080 return this.applyTemplate.apply(this, arguments);
54085 Roo.XTemplate.from = function(el){
54086 el = Roo.getDom(el);
54087 return new Roo.XTemplate(el.value || el.innerHTML);
54089 * Original code for Roojs - LGPL
54090 * <script type="text/javascript">
54094 * @class Roo.XComponent
54095 * A delayed Element creator...
54096 * Or a way to group chunks of interface together.
54098 * Mypart.xyx = new Roo.XComponent({
54100 parent : 'Mypart.xyz', // empty == document.element.!!
54104 disabled : function() {}
54106 tree : function() { // return an tree of xtype declared components
54110 xtype : 'NestedLayoutPanel',
54117 * It can be used to build a big heiracy, with parent etc.
54118 * or you can just use this to render a single compoent to a dom element
54119 * MYPART.render(Roo.Element | String(id) | dom_element )
54121 * @extends Roo.util.Observable
54123 * @param cfg {Object} configuration of component
54126 Roo.XComponent = function(cfg) {
54127 Roo.apply(this, cfg);
54131 * Fires when this the componnt is built
54132 * @param {Roo.XComponent} c the component
54137 this.region = this.region || 'center'; // default..
54138 Roo.XComponent.register(this);
54139 this.modules = false;
54140 this.el = false; // where the layout goes..
54144 Roo.extend(Roo.XComponent, Roo.util.Observable, {
54147 * The created element (with Roo.factory())
54148 * @type {Roo.Layout}
54154 * for BC - use el in new code
54155 * @type {Roo.Layout}
54161 * for BC - use el in new code
54162 * @type {Roo.Layout}
54167 * @cfg {Function|boolean} disabled
54168 * If this module is disabled by some rule, return true from the funtion
54173 * @cfg {String} parent
54174 * Name of parent element which it get xtype added to..
54179 * @cfg {String} order
54180 * Used to set the order in which elements are created (usefull for multiple tabs)
54185 * @cfg {String} name
54186 * String to display while loading.
54190 * @cfg {String} region
54191 * Region to render component to (defaults to center)
54196 * @cfg {Array} items
54197 * A single item array - the first element is the root of the tree..
54198 * It's done this way to stay compatible with the Xtype system...
54204 * The method that retuns the tree of parts that make up this compoennt
54211 * render element to dom or tree
54212 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
54215 render : function(el)
54219 var hp = this.parent ? 1 : 0;
54221 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
54222 // if parent is a '#.....' string, then let's use that..
54223 var ename = this.parent.substr(1)
54224 this.parent = false;
54225 el = Roo.get(ename);
54227 Roo.log("Warning - element can not be found :#" + ename );
54233 if (!this.parent) {
54235 el = el ? Roo.get(el) : false;
54237 // it's a top level one..
54239 el : new Roo.BorderLayout(el || document.body, {
54245 tabPosition: 'top',
54246 //resizeTabs: true,
54247 alwaysShowTabs: el && hp? false : true,
54248 hideTabs: el || !hp ? true : false,
54255 if (!this.parent.el) {
54256 // probably an old style ctor, which has been disabled.
54260 // The 'tree' method is '_tree now'
54262 var tree = this._tree ? this._tree() : this.tree();
54263 tree.region = tree.region || this.region;
54264 this.el = this.parent.el.addxtype(tree);
54265 this.fireEvent('built', this);
54267 this.panel = this.el;
54268 this.layout = this.panel.layout;
54269 this.parentLayout = this.parent.layout || false;
54275 Roo.apply(Roo.XComponent, {
54277 * @property hideProgress
54278 * true to disable the building progress bar.. usefull on single page renders.
54281 hideProgress : false,
54283 * @property buildCompleted
54284 * True when the builder has completed building the interface.
54287 buildCompleted : false,
54290 * @property topModule
54291 * the upper most module - uses document.element as it's constructor.
54298 * @property modules
54299 * array of modules to be created by registration system.
54300 * @type {Array} of Roo.XComponent
54305 * @property elmodules
54306 * array of modules to be created by which use #ID
54307 * @type {Array} of Roo.XComponent
54314 * Register components to be built later.
54316 * This solves the following issues
54317 * - Building is not done on page load, but after an authentication process has occured.
54318 * - Interface elements are registered on page load
54319 * - Parent Interface elements may not be loaded before child, so this handles that..
54326 module : 'Pman.Tab.projectMgr',
54328 parent : 'Pman.layout',
54329 disabled : false, // or use a function..
54332 * * @param {Object} details about module
54334 register : function(obj) {
54336 Roo.XComponent.event.fireEvent('register', obj);
54337 switch(typeof(obj.disabled) ) {
54343 if ( obj.disabled() ) {
54349 if (obj.disabled) {
54355 this.modules.push(obj);
54359 * convert a string to an object..
54360 * eg. 'AAA.BBB' -> finds AAA.BBB
54364 toObject : function(str)
54366 if (!str || typeof(str) == 'object') {
54369 if (str.substring(0,1) == '#') {
54373 var ar = str.split('.');
54378 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
54380 throw "Module not found : " + str;
54384 throw "Module not found : " + str;
54386 Roo.each(ar, function(e) {
54387 if (typeof(o[e]) == 'undefined') {
54388 throw "Module not found : " + str;
54399 * move modules into their correct place in the tree..
54402 preBuild : function ()
54405 Roo.each(this.modules , function (obj)
54407 Roo.XComponent.event.fireEvent('beforebuild', obj);
54409 var opar = obj.parent;
54411 obj.parent = this.toObject(opar);
54413 Roo.log("parent:toObject failed: " + e.toString());
54418 Roo.debug && Roo.log("GOT top level module");
54419 Roo.debug && Roo.log(obj);
54420 obj.modules = new Roo.util.MixedCollection(false,
54421 function(o) { return o.order + '' }
54423 this.topModule = obj;
54426 // parent is a string (usually a dom element name..)
54427 if (typeof(obj.parent) == 'string') {
54428 this.elmodules.push(obj);
54431 if (obj.parent.constructor != Roo.XComponent) {
54432 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
54434 if (!obj.parent.modules) {
54435 obj.parent.modules = new Roo.util.MixedCollection(false,
54436 function(o) { return o.order + '' }
54439 if (obj.parent.disabled) {
54440 obj.disabled = true;
54442 obj.parent.modules.add(obj);
54447 * make a list of modules to build.
54448 * @return {Array} list of modules.
54451 buildOrder : function()
54454 var cmp = function(a,b) {
54455 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
54457 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
54458 throw "No top level modules to build";
54461 // make a flat list in order of modules to build.
54462 var mods = this.topModule ? [ this.topModule ] : [];
54464 // elmodules (is a list of DOM based modules )
54465 Roo.each(this.elmodules, function(e) {
54470 // add modules to their parents..
54471 var addMod = function(m) {
54472 Roo.debug && Roo.log("build Order: add: " + m.name);
54475 if (m.modules && !m.disabled) {
54476 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
54477 m.modules.keySort('ASC', cmp );
54478 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
54480 m.modules.each(addMod);
54482 Roo.debug && Roo.log("build Order: no child modules");
54484 // not sure if this is used any more..
54486 m.finalize.name = m.name + " (clean up) ";
54487 mods.push(m.finalize);
54491 if (this.topModule) {
54492 this.topModule.modules.keySort('ASC', cmp );
54493 this.topModule.modules.each(addMod);
54499 * Build the registered modules.
54500 * @param {Object} parent element.
54501 * @param {Function} optional method to call after module has been added.
54509 var mods = this.buildOrder();
54511 //this.allmods = mods;
54512 //Roo.debug && Roo.log(mods);
54514 if (!mods.length) { // should not happen
54515 throw "NO modules!!!";
54519 var msg = "Building Interface...";
54520 // flash it up as modal - so we store the mask!?
54521 if (!this.hideProgress) {
54522 Roo.MessageBox.show({ title: 'loading' });
54523 Roo.MessageBox.show({
54524 title: "Please wait...",
54533 var total = mods.length;
54536 var progressRun = function() {
54537 if (!mods.length) {
54538 Roo.debug && Roo.log('hide?');
54539 if (!this.hideProgress) {
54540 Roo.MessageBox.hide();
54542 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
54548 var m = mods.shift();
54551 Roo.debug && Roo.log(m);
54552 // not sure if this is supported any more.. - modules that are are just function
54553 if (typeof(m) == 'function') {
54555 return progressRun.defer(10, _this);
54559 msg = "Building Interface " + (total - mods.length) +
54561 (m.name ? (' - ' + m.name) : '');
54562 Roo.debug && Roo.log(msg);
54563 if (!this.hideProgress) {
54564 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
54568 // is the module disabled?
54569 var disabled = (typeof(m.disabled) == 'function') ?
54570 m.disabled.call(m.module.disabled) : m.disabled;
54574 return progressRun(); // we do not update the display!
54582 // it's 10 on top level, and 1 on others??? why...
54583 return progressRun.defer(10, _this);
54586 progressRun.defer(1, _this);
54600 * wrapper for event.on - aliased later..
54601 * Typically use to register a event handler for register:
54603 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
54612 Roo.XComponent.event = new Roo.util.Observable({
54616 * Fires when an Component is registered,
54617 * set the disable property on the Component to stop registration.
54618 * @param {Roo.XComponent} c the component being registerd.
54623 * @event beforebuild
54624 * Fires before each Component is built
54625 * can be used to apply permissions.
54626 * @param {Roo.XComponent} c the component being registerd.
54629 'beforebuild' : true,
54631 * @event buildcomplete
54632 * Fires on the top level element when all elements have been built
54633 * @param {Roo.XComponent} the top level component.
54635 'buildcomplete' : true
54640 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
54641 //<script type="text/javascript">
54646 * @extends Roo.LayoutDialog
54647 * A generic Login Dialog..... - only one needed in theory!?!?
54649 * Fires XComponent builder on success...
54652 * username,password, lang = for login actions.
54653 * check = 1 for periodic checking that sesion is valid.
54654 * passwordRequest = email request password
54655 * logout = 1 = to logout
54657 * Affects: (this id="????" elements)
54658 * loading (removed) (used to indicate application is loading)
54659 * loading-mask (hides) (used to hide application when it's building loading)
54665 * Myapp.login = Roo.Login({
54681 Roo.Login = function(cfg)
54687 Roo.apply(this,cfg);
54689 Roo.onReady(function() {
54695 Roo.Login.superclass.constructor.call(this, this);
54696 //this.addxtype(this.items[0]);
54702 Roo.extend(Roo.Login, Roo.LayoutDialog, {
54705 * @cfg {String} method
54706 * Method used to query for login details.
54711 * @cfg {String} url
54712 * URL to query login data. - eg. baseURL + '/Login.php'
54718 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
54723 * @property checkFails
54724 * Number of times we have attempted to get authentication check, and failed.
54729 * @property intervalID
54730 * The window interval that does the constant login checking.
54736 onLoad : function() // called on page load...
54740 if (Roo.get('loading')) { // clear any loading indicator..
54741 Roo.get('loading').remove();
54744 //this.switchLang('en'); // set the language to english..
54747 success: function(response, opts) { // check successfull...
54749 var res = this.processResponse(response);
54750 this.checkFails =0;
54751 if (!res.success) { // error!
54752 this.checkFails = 5;
54753 //console.log('call failure');
54754 return this.failure(response,opts);
54757 if (!res.data.id) { // id=0 == login failure.
54758 return this.show();
54762 //console.log(success);
54763 this.fillAuth(res.data);
54764 this.checkFails =0;
54765 Roo.XComponent.build();
54767 failure : this.show
54773 check: function(cfg) // called every so often to refresh cookie etc..
54775 if (cfg.again) { // could be undefined..
54778 this.checkFails = 0;
54781 if (this.sending) {
54782 if ( this.checkFails > 4) {
54783 Roo.MessageBox.alert("Error",
54784 "Error getting authentication status. - try reloading, or wait a while", function() {
54785 _this.sending = false;
54790 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
54793 this.sending = true;
54800 method: this.method,
54801 success: cfg.success || this.success,
54802 failure : cfg.failure || this.failure,
54812 window.onbeforeunload = function() { }; // false does not work for IE..
54822 failure : function() {
54823 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
54824 document.location = document.location.toString() + '?ts=' + Math.random();
54828 success : function() {
54829 _this.user = false;
54830 this.checkFails =0;
54832 document.location = document.location.toString() + '?ts=' + Math.random();
54839 processResponse : function (response)
54843 res = Roo.decode(response.responseText);
54845 if (typeof(res) != 'object') {
54846 res = { success : false, errorMsg : res, errors : true };
54848 if (typeof(res.success) == 'undefined') {
54849 res.success = false;
54853 res = { success : false, errorMsg : response.responseText, errors : true };
54858 success : function(response, opts) // check successfull...
54860 this.sending = false;
54861 var res = this.processResponse(response);
54862 if (!res.success) {
54863 return this.failure(response, opts);
54865 if (!res.data || !res.data.id) {
54866 return this.failure(response,opts);
54868 //console.log(res);
54869 this.fillAuth(res.data);
54871 this.checkFails =0;
54876 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
54878 this.authUser = -1;
54879 this.sending = false;
54880 var res = this.processResponse(response);
54881 //console.log(res);
54882 if ( this.checkFails > 2) {
54884 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
54885 "Error getting authentication status. - try reloading");
54888 opts.callCfg.again = true;
54889 this.check.defer(1000, this, [ opts.callCfg ]);
54895 fillAuth: function(au) {
54896 this.startAuthCheck();
54897 this.authUserId = au.id;
54898 this.authUser = au;
54899 this.lastChecked = new Date();
54900 this.fireEvent('refreshed', au);
54901 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
54902 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
54903 au.lang = au.lang || 'en';
54904 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
54905 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
54906 this.switchLang(au.lang );
54909 // open system... - -on setyp..
54910 if (this.authUserId < 0) {
54911 Roo.MessageBox.alert("Warning",
54912 "This is an open system - please set up a admin user with a password.");
54915 //Pman.onload(); // which should do nothing if it's a re-auth result...
54920 startAuthCheck : function() // starter for timeout checking..
54922 if (this.intervalID) { // timer already in place...
54926 this.intervalID = window.setInterval(function() {
54927 _this.check(false);
54928 }, 120000); // every 120 secs = 2mins..
54934 switchLang : function (lang)
54936 _T = typeof(_T) == 'undefined' ? false : _T;
54937 if (!_T || !lang.length) {
54941 if (!_T && lang != 'en') {
54942 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
54946 if (typeof(_T.en) == 'undefined') {
54948 Roo.apply(_T.en, _T);
54951 if (typeof(_T[lang]) == 'undefined') {
54952 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
54957 Roo.apply(_T, _T[lang]);
54958 // just need to set the text values for everything...
54960 /* this will not work ...
54964 function formLabel(name, val) {
54965 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
54968 formLabel('password', "Password"+':');
54969 formLabel('username', "Email Address"+':');
54970 formLabel('lang', "Language"+':');
54971 this.dialog.setTitle("Login");
54972 this.dialog.buttons[0].setText("Forgot Password");
54973 this.dialog.buttons[1].setText("Login");
54992 collapsible: false,
54994 center: { // needed??
54997 // tabPosition: 'top',
55000 alwaysShowTabs: false
55004 show : function(dlg)
55006 //console.log(this);
55007 this.form = this.layout.getRegion('center').activePanel.form;
55008 this.form.dialog = dlg;
55009 this.buttons[0].form = this.form;
55010 this.buttons[0].dialog = dlg;
55011 this.buttons[1].form = this.form;
55012 this.buttons[1].dialog = dlg;
55014 //this.resizeToLogo.defer(1000,this);
55015 // this is all related to resizing for logos..
55016 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
55018 // this.resizeToLogo.defer(1000,this);
55021 //var w = Ext.lib.Dom.getViewWidth() - 100;
55022 //var h = Ext.lib.Dom.getViewHeight() - 100;
55023 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
55025 if (this.disabled) {
55030 if (this.user.id < 0) { // used for inital setup situations.
55034 if (this.intervalID) {
55035 // remove the timer
55036 window.clearInterval(this.intervalID);
55037 this.intervalID = false;
55041 if (Roo.get('loading')) {
55042 Roo.get('loading').remove();
55044 if (Roo.get('loading-mask')) {
55045 Roo.get('loading-mask').hide();
55048 //incomming._node = tnode;
55050 //this.dialog.modal = !modal;
55051 //this.dialog.show();
55055 this.form.setValues({
55056 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
55057 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
55060 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
55061 if (this.form.findField('username').getValue().length > 0 ){
55062 this.form.findField('password').focus();
55064 this.form.findField('username').focus();
55072 xtype : 'ContentPanel',
55084 style : 'margin: 10px;',
55087 actionfailed : function(f, act) {
55088 // form can return { errors: .... }
55090 //act.result.errors // invalid form element list...
55091 //act.result.errorMsg// invalid form element list...
55093 this.dialog.el.unmask();
55094 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
55095 "Login failed - communication error - try again.");
55098 actioncomplete: function(re, act) {
55100 Roo.state.Manager.set(
55101 this.dialog.realm + '.username',
55102 this.findField('username').getValue()
55104 Roo.state.Manager.set(
55105 this.dialog.realm + '.lang',
55106 this.findField('lang').getValue()
55109 this.dialog.fillAuth(act.result.data);
55111 this.dialog.hide();
55113 if (Roo.get('loading-mask')) {
55114 Roo.get('loading-mask').show();
55116 Roo.XComponent.build();
55124 xtype : 'TextField',
55126 fieldLabel: "Email Address",
55129 autoCreate : {tag: "input", type: "text", size: "20"}
55132 xtype : 'TextField',
55134 fieldLabel: "Password",
55135 inputType: 'password',
55138 autoCreate : {tag: "input", type: "text", size: "20"},
55140 specialkey : function(e,ev) {
55141 if (ev.keyCode == 13) {
55142 this.form.dialog.el.mask("Logging in");
55143 this.form.doAction('submit', {
55144 url: this.form.dialog.url,
55145 method: this.form.dialog.method
55152 xtype : 'ComboBox',
55154 fieldLabel: "Language",
55157 xtype : 'SimpleStore',
55158 fields: ['lang', 'ldisp'],
55160 [ 'en', 'English' ],
55161 [ 'zh_HK' , '\u7E41\u4E2D' ],
55162 [ 'zh_CN', '\u7C21\u4E2D' ]
55166 valueField : 'lang',
55167 hiddenName: 'lang',
55169 displayField:'ldisp',
55173 triggerAction: 'all',
55174 emptyText:'Select a Language...',
55175 selectOnFocus:true,
55177 select : function(cb, rec, ix) {
55178 this.form.switchLang(rec.data.lang);
55194 text : "Forgot Password",
55196 click : function() {
55197 //console.log(this);
55198 var n = this.form.findField('username').getValue();
55200 Roo.MessageBox.alert("Error", "Fill in your email address");
55204 url: this.dialog.url,
55208 method: this.dialog.method,
55209 success: function(response, opts) { // check successfull...
55211 var res = this.dialog.processResponse(response);
55212 if (!res.success) { // error!
55213 Roo.MessageBox.alert("Error" ,
55214 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
55217 Roo.MessageBox.alert("Notice" ,
55218 "Please check you email for the Password Reset message");
55220 failure : function() {
55221 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
55234 click : function () {
55236 this.dialog.el.mask("Logging in");
55237 this.form.doAction('submit', {
55238 url: this.dialog.url,
55239 method: this.dialog.method