4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours
1010 T CST Timezone setting of the machine running the code
1011 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1014 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1016 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1017 document.write(dt.format('Y-m-d')); //2007-01-10
1018 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1019 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1022 * Here are some standard date/time patterns that you might find helpful. They
1023 * are not part of the source of Date.js, but to use them you can simply copy this
1024 * block of code into any script that is included after Date.js and they will also become
1025 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1028 ISO8601Long:"Y-m-d H:i:s",
1029 ISO8601Short:"Y-m-d",
1031 LongDate: "l, F d, Y",
1032 FullDateTime: "l, F d, Y g:i:s A",
1035 LongTime: "g:i:s A",
1036 SortableDateTime: "Y-m-d\\TH:i:s",
1037 UniversalSortableDateTime: "Y-m-d H:i:sO",
1044 var dt = new Date();
1045 document.write(dt.format(Date.patterns.ShortDate));
1050 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1051 * They generate precompiled functions from date formats instead of parsing and
1052 * processing the pattern every time you format a date. These functions are available
1053 * on every Date object (any javascript function).
1055 * The original article and download are here:
1056 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1063 Returns the number of milliseconds between this date and date
1064 @param {Date} date (optional) Defaults to now
1065 @return {Number} The diff in milliseconds
1066 @member Date getElapsed
1068 Date.prototype.getElapsed = function(date) {
1069 return Math.abs((date || new Date()).getTime()-this.getTime());
1071 // was in date file..
1075 Date.parseFunctions = {count:0};
1077 Date.parseRegexes = [];
1079 Date.formatFunctions = {count:0};
1082 Date.prototype.dateFormat = function(format) {
1083 if (Date.formatFunctions[format] == null) {
1084 Date.createNewFormat(format);
1086 var func = Date.formatFunctions[format];
1087 return this[func]();
1092 * Formats a date given the supplied format string
1093 * @param {String} format The format string
1094 * @return {String} The formatted date
1097 Date.prototype.format = Date.prototype.dateFormat;
1100 Date.createNewFormat = function(format) {
1101 var funcName = "format" + Date.formatFunctions.count++;
1102 Date.formatFunctions[format] = funcName;
1103 var code = "Date.prototype." + funcName + " = function(){return ";
1104 var special = false;
1106 for (var i = 0; i < format.length; ++i) {
1107 ch = format.charAt(i);
1108 if (!special && ch == "\\") {
1113 code += "'" + String.escape(ch) + "' + ";
1116 code += Date.getFormatCode(ch);
1119 /** eval:var:zzzzzzzzzzzzz */
1120 eval(code.substring(0, code.length - 3) + ";}");
1124 Date.getFormatCode = function(character) {
1125 switch (character) {
1127 return "String.leftPad(this.getDate(), 2, '0') + ";
1129 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1131 return "this.getDate() + ";
1133 return "Date.dayNames[this.getDay()] + ";
1135 return "this.getSuffix() + ";
1137 return "this.getDay() + ";
1139 return "this.getDayOfYear() + ";
1141 return "this.getWeekOfYear() + ";
1143 return "Date.monthNames[this.getMonth()] + ";
1145 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1147 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1149 return "(this.getMonth() + 1) + ";
1151 return "this.getDaysInMonth() + ";
1153 return "(this.isLeapYear() ? 1 : 0) + ";
1155 return "this.getFullYear() + ";
1157 return "('' + this.getFullYear()).substring(2, 4) + ";
1159 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1161 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1163 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1165 return "this.getHours() + ";
1167 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1169 return "String.leftPad(this.getHours(), 2, '0') + ";
1171 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1173 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1175 return "this.getGMTOffset() + ";
1177 return "this.getTimezone() + ";
1179 return "(this.getTimezoneOffset() * -60) + ";
1181 return "'" + String.escape(character) + "' + ";
1186 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1187 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1188 * the date format that is not specified will default to the current date value for that part. Time parts can also
1189 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1190 * string or the parse operation will fail.
1193 //dt = Fri May 25 2007 (current date)
1194 var dt = new Date();
1196 //dt = Thu May 25 2006 (today's month/day in 2006)
1197 dt = Date.parseDate("2006", "Y");
1199 //dt = Sun Jan 15 2006 (all date parts specified)
1200 dt = Date.parseDate("2006-1-15", "Y-m-d");
1202 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1203 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1205 * @param {String} input The unparsed date as a string
1206 * @param {String} format The format the date is in
1207 * @return {Date} The parsed date
1210 Date.parseDate = function(input, format) {
1211 if (Date.parseFunctions[format] == null) {
1212 Date.createParser(format);
1214 var func = Date.parseFunctions[format];
1215 return Date[func](input);
1220 Date.createParser = function(format) {
1221 var funcName = "parse" + Date.parseFunctions.count++;
1222 var regexNum = Date.parseRegexes.length;
1223 var currentGroup = 1;
1224 Date.parseFunctions[format] = funcName;
1226 var code = "Date." + funcName + " = function(input){\n"
1227 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1228 + "var d = new Date();\n"
1229 + "y = d.getFullYear();\n"
1230 + "m = d.getMonth();\n"
1231 + "d = d.getDate();\n"
1232 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1233 + "if (results && results.length > 0) {";
1236 var special = false;
1238 for (var i = 0; i < format.length; ++i) {
1239 ch = format.charAt(i);
1240 if (!special && ch == "\\") {
1245 regex += String.escape(ch);
1248 var obj = Date.formatCodeToRegex(ch, currentGroup);
1249 currentGroup += obj.g;
1251 if (obj.g && obj.c) {
1257 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1258 + "{v = new Date(y, m, d, h, i, s);}\n"
1259 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1260 + "{v = new Date(y, m, d, h, i);}\n"
1261 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1262 + "{v = new Date(y, m, d, h);}\n"
1263 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1264 + "{v = new Date(y, m, d);}\n"
1265 + "else if (y >= 0 && m >= 0)\n"
1266 + "{v = new Date(y, m);}\n"
1267 + "else if (y >= 0)\n"
1268 + "{v = new Date(y);}\n"
1269 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1270 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1271 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1274 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1275 /** eval:var:zzzzzzzzzzzzz */
1280 Date.formatCodeToRegex = function(character, currentGroup) {
1281 switch (character) {
1285 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1288 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1289 s:"(\\d{1,2})"}; // day of month without leading zeroes
1292 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1293 s:"(\\d{2})"}; // day of month with leading zeroes
1297 s:"(?:" + Date.dayNames.join("|") + ")"};
1301 s:"(?:st|nd|rd|th)"};
1316 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1317 s:"(" + Date.monthNames.join("|") + ")"};
1320 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1321 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1324 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1325 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1328 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1329 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1340 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1344 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1345 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1349 c:"if (results[" + currentGroup + "] == 'am') {\n"
1350 + "if (h == 12) { h = 0; }\n"
1351 + "} else { if (h < 12) { h += 12; }}",
1355 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1356 + "if (h == 12) { h = 0; }\n"
1357 + "} else { if (h < 12) { h += 12; }}",
1362 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1363 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1371 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1375 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1380 "o = results[", currentGroup, "];\n",
1381 "var sn = o.substring(0,1);\n", // get + / - sign
1382 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1383 "var mn = o.substring(3,5) % 60;\n", // get minutes
1384 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1385 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1394 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1395 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1396 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1400 s:String.escape(character)};
1405 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1406 * @return {String} The abbreviated timezone name (e.g. 'CST')
1408 Date.prototype.getTimezone = function() {
1409 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1413 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1414 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1416 Date.prototype.getGMTOffset = function() {
1417 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1418 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1419 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1423 * Get the numeric day number of the year, adjusted for leap year.
1424 * @return {Number} 0 through 364 (365 in leap years)
1426 Date.prototype.getDayOfYear = function() {
1428 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1429 for (var i = 0; i < this.getMonth(); ++i) {
1430 num += Date.daysInMonth[i];
1432 return num + this.getDate() - 1;
1436 * Get the string representation of the numeric week number of the year
1437 * (equivalent to the format specifier 'W').
1438 * @return {String} '00' through '52'
1440 Date.prototype.getWeekOfYear = function() {
1441 // Skip to Thursday of this week
1442 var now = this.getDayOfYear() + (4 - this.getDay());
1443 // Find the first Thursday of the year
1444 var jan1 = new Date(this.getFullYear(), 0, 1);
1445 var then = (7 - jan1.getDay() + 4);
1446 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1450 * Whether or not the current date is in a leap year.
1451 * @return {Boolean} True if the current date is in a leap year, else false
1453 Date.prototype.isLeapYear = function() {
1454 var year = this.getFullYear();
1455 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1459 * Get the first day of the current month, adjusted for leap year. The returned value
1460 * is the numeric day index within the week (0-6) which can be used in conjunction with
1461 * the {@link #monthNames} array to retrieve the textual day name.
1464 var dt = new Date('1/10/2007');
1465 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1467 * @return {Number} The day number (0-6)
1469 Date.prototype.getFirstDayOfMonth = function() {
1470 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1471 return (day < 0) ? (day + 7) : day;
1475 * Get the last day of the current month, adjusted for leap year. The returned value
1476 * is the numeric day index within the week (0-6) which can be used in conjunction with
1477 * the {@link #monthNames} array to retrieve the textual day name.
1480 var dt = new Date('1/10/2007');
1481 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1483 * @return {Number} The day number (0-6)
1485 Date.prototype.getLastDayOfMonth = function() {
1486 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1487 return (day < 0) ? (day + 7) : day;
1492 * Get the first date of this date's month
1495 Date.prototype.getFirstDateOfMonth = function() {
1496 return new Date(this.getFullYear(), this.getMonth(), 1);
1500 * Get the last date of this date's month
1503 Date.prototype.getLastDateOfMonth = function() {
1504 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1507 * Get the number of days in the current month, adjusted for leap year.
1508 * @return {Number} The number of days in the month
1510 Date.prototype.getDaysInMonth = function() {
1511 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1512 return Date.daysInMonth[this.getMonth()];
1516 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1517 * @return {String} 'st, 'nd', 'rd' or 'th'
1519 Date.prototype.getSuffix = function() {
1520 switch (this.getDate()) {
1537 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1540 * An array of textual month names.
1541 * Override these values for international dates, for example...
1542 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1561 * An array of textual day names.
1562 * Override these values for international dates, for example...
1563 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1579 Date.monthNumbers = {
1594 * Creates and returns a new Date instance with the exact same date value as the called instance.
1595 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1596 * variable will also be changed. When the intention is to create a new variable that will not
1597 * modify the original instance, you should create a clone.
1599 * Example of correctly cloning a date:
1602 var orig = new Date('10/1/2006');
1605 document.write(orig); //returns 'Thu Oct 05 2006'!
1608 var orig = new Date('10/1/2006');
1609 var copy = orig.clone();
1611 document.write(orig); //returns 'Thu Oct 01 2006'
1613 * @return {Date} The new Date instance
1615 Date.prototype.clone = function() {
1616 return new Date(this.getTime());
1620 * Clears any time information from this date
1621 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1622 @return {Date} this or the clone
1624 Date.prototype.clearTime = function(clone){
1626 return this.clone().clearTime();
1631 this.setMilliseconds(0);
1636 // safari setMonth is broken
1638 Date.brokenSetMonth = Date.prototype.setMonth;
1639 Date.prototype.setMonth = function(num){
1641 var n = Math.ceil(-num);
1642 var back_year = Math.ceil(n/12);
1643 var month = (n % 12) ? 12 - n % 12 : 0 ;
1644 this.setFullYear(this.getFullYear() - back_year);
1645 return Date.brokenSetMonth.call(this, month);
1647 return Date.brokenSetMonth.apply(this, arguments);
1652 /** Date interval constant
1656 /** Date interval constant
1660 /** Date interval constant
1664 /** Date interval constant
1668 /** Date interval constant
1672 /** Date interval constant
1676 /** Date interval constant
1682 * Provides a convenient method of performing basic date arithmetic. This method
1683 * does not modify the Date instance being called - it creates and returns
1684 * a new Date instance containing the resulting date value.
1689 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1690 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1692 //Negative values will subtract correctly:
1693 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1694 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1696 //You can even chain several calls together in one line!
1697 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1698 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1701 * @param {String} interval A valid date interval enum value
1702 * @param {Number} value The amount to add to the current date
1703 * @return {Date} The new Date instance
1705 Date.prototype.add = function(interval, value){
1706 var d = this.clone();
1707 if (!interval || value === 0) return d;
1708 switch(interval.toLowerCase()){
1710 d.setMilliseconds(this.getMilliseconds() + value);
1713 d.setSeconds(this.getSeconds() + value);
1716 d.setMinutes(this.getMinutes() + value);
1719 d.setHours(this.getHours() + value);
1722 d.setDate(this.getDate() + value);
1725 var day = this.getDate();
1727 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1730 d.setMonth(this.getMonth() + value);
1733 d.setFullYear(this.getFullYear() + value);
1739 * Ext JS Library 1.1.1
1740 * Copyright(c) 2006-2007, Ext JS, LLC.
1742 * Originally Released Under LGPL - original licence link has changed is not relivant.
1745 * <script type="text/javascript">
1749 getViewWidth : function(full) {
1750 return full ? this.getDocumentWidth() : this.getViewportWidth();
1753 getViewHeight : function(full) {
1754 return full ? this.getDocumentHeight() : this.getViewportHeight();
1757 getDocumentHeight: function() {
1758 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1759 return Math.max(scrollHeight, this.getViewportHeight());
1762 getDocumentWidth: function() {
1763 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1764 return Math.max(scrollWidth, this.getViewportWidth());
1767 getViewportHeight: function() {
1768 var height = self.innerHeight;
1769 var mode = document.compatMode;
1771 if ((mode || Roo.isIE) && !Roo.isOpera) {
1772 height = (mode == "CSS1Compat") ?
1773 document.documentElement.clientHeight :
1774 document.body.clientHeight;
1780 getViewportWidth: function() {
1781 var width = self.innerWidth;
1782 var mode = document.compatMode;
1784 if (mode || Roo.isIE) {
1785 width = (mode == "CSS1Compat") ?
1786 document.documentElement.clientWidth :
1787 document.body.clientWidth;
1792 isAncestor : function(p, c) {
1799 if (p.contains && !Roo.isSafari) {
1800 return p.contains(c);
1801 } else if (p.compareDocumentPosition) {
1802 return !!(p.compareDocumentPosition(c) & 16);
1804 var parent = c.parentNode;
1809 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1812 parent = parent.parentNode;
1818 getRegion : function(el) {
1819 return Roo.lib.Region.getRegion(el);
1822 getY : function(el) {
1823 return this.getXY(el)[1];
1826 getX : function(el) {
1827 return this.getXY(el)[0];
1830 getXY : function(el) {
1831 var p, pe, b, scroll, bd = document.body;
1832 el = Roo.getDom(el);
1833 var fly = Roo.lib.AnimBase.fly;
1834 if (el.getBoundingClientRect) {
1835 b = el.getBoundingClientRect();
1836 scroll = fly(document).getScroll();
1837 return [b.left + scroll.left, b.top + scroll.top];
1843 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1850 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1857 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1858 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1865 if (p != el && pe.getStyle('overflow') != 'visible') {
1873 if (Roo.isSafari && hasAbsolute) {
1878 if (Roo.isGecko && !hasAbsolute) {
1880 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1881 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1885 while (p && p != bd) {
1886 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1898 setXY : function(el, xy) {
1899 el = Roo.fly(el, '_setXY');
1901 var pts = el.translatePoints(xy);
1902 if (xy[0] !== false) {
1903 el.dom.style.left = pts.left + "px";
1905 if (xy[1] !== false) {
1906 el.dom.style.top = pts.top + "px";
1910 setX : function(el, x) {
1911 this.setXY(el, [x, false]);
1914 setY : function(el, y) {
1915 this.setXY(el, [false, y]);
1919 * Portions of this file are based on pieces of Yahoo User Interface Library
1920 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1921 * YUI licensed under the BSD License:
1922 * http://developer.yahoo.net/yui/license.txt
1923 * <script type="text/javascript">
1927 Roo.lib.Event = function() {
1928 var loadComplete = false;
1930 var unloadListeners = [];
1932 var onAvailStack = [];
1934 var lastError = null;
1947 startInterval: function() {
1948 if (!this._interval) {
1950 var callback = function() {
1951 self._tryPreloadAttach();
1953 this._interval = setInterval(callback, this.POLL_INTERVAL);
1958 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1959 onAvailStack.push({ id: p_id,
1962 override: p_override,
1963 checkReady: false });
1965 retryCount = this.POLL_RETRYS;
1966 this.startInterval();
1970 addListener: function(el, eventName, fn) {
1971 el = Roo.getDom(el);
1976 if ("unload" == eventName) {
1977 unloadListeners[unloadListeners.length] =
1978 [el, eventName, fn];
1982 var wrappedFn = function(e) {
1983 return fn(Roo.lib.Event.getEvent(e));
1986 var li = [el, eventName, fn, wrappedFn];
1988 var index = listeners.length;
1989 listeners[index] = li;
1991 this.doAdd(el, eventName, wrappedFn, false);
1997 removeListener: function(el, eventName, fn) {
2000 el = Roo.getDom(el);
2003 return this.purgeElement(el, false, eventName);
2007 if ("unload" == eventName) {
2009 for (i = 0,len = unloadListeners.length; i < len; i++) {
2010 var li = unloadListeners[i];
2013 li[1] == eventName &&
2015 unloadListeners.splice(i, 1);
2023 var cacheItem = null;
2026 var index = arguments[3];
2028 if ("undefined" == typeof index) {
2029 index = this._getCacheIndex(el, eventName, fn);
2033 cacheItem = listeners[index];
2036 if (!el || !cacheItem) {
2040 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2042 delete listeners[index][this.WFN];
2043 delete listeners[index][this.FN];
2044 listeners.splice(index, 1);
2051 getTarget: function(ev, resolveTextNode) {
2052 ev = ev.browserEvent || ev;
2053 var t = ev.target || ev.srcElement;
2054 return this.resolveTextNode(t);
2058 resolveTextNode: function(node) {
2059 if (Roo.isSafari && node && 3 == node.nodeType) {
2060 return node.parentNode;
2067 getPageX: function(ev) {
2068 ev = ev.browserEvent || ev;
2070 if (!x && 0 !== x) {
2071 x = ev.clientX || 0;
2074 x += this.getScroll()[1];
2082 getPageY: function(ev) {
2083 ev = ev.browserEvent || ev;
2085 if (!y && 0 !== y) {
2086 y = ev.clientY || 0;
2089 y += this.getScroll()[0];
2098 getXY: function(ev) {
2099 ev = ev.browserEvent || ev;
2100 return [this.getPageX(ev), this.getPageY(ev)];
2104 getRelatedTarget: function(ev) {
2105 ev = ev.browserEvent || ev;
2106 var t = ev.relatedTarget;
2108 if (ev.type == "mouseout") {
2110 } else if (ev.type == "mouseover") {
2115 return this.resolveTextNode(t);
2119 getTime: function(ev) {
2120 ev = ev.browserEvent || ev;
2122 var t = new Date().getTime();
2126 this.lastError = ex;
2135 stopEvent: function(ev) {
2136 this.stopPropagation(ev);
2137 this.preventDefault(ev);
2141 stopPropagation: function(ev) {
2142 ev = ev.browserEvent || ev;
2143 if (ev.stopPropagation) {
2144 ev.stopPropagation();
2146 ev.cancelBubble = true;
2151 preventDefault: function(ev) {
2152 ev = ev.browserEvent || ev;
2153 if(ev.preventDefault) {
2154 ev.preventDefault();
2156 ev.returnValue = false;
2161 getEvent: function(e) {
2162 var ev = e || window.event;
2164 var c = this.getEvent.caller;
2166 ev = c.arguments[0];
2167 if (ev && Event == ev.constructor) {
2177 getCharCode: function(ev) {
2178 ev = ev.browserEvent || ev;
2179 return ev.charCode || ev.keyCode || 0;
2183 _getCacheIndex: function(el, eventName, fn) {
2184 for (var i = 0,len = listeners.length; i < len; ++i) {
2185 var li = listeners[i];
2187 li[this.FN] == fn &&
2188 li[this.EL] == el &&
2189 li[this.TYPE] == eventName) {
2201 getEl: function(id) {
2202 return document.getElementById(id);
2206 clearCache: function() {
2210 _load: function(e) {
2211 loadComplete = true;
2212 var EU = Roo.lib.Event;
2216 EU.doRemove(window, "load", EU._load);
2221 _tryPreloadAttach: function() {
2230 var tryAgain = !loadComplete;
2232 tryAgain = (retryCount > 0);
2237 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2238 var item = onAvailStack[i];
2240 var el = this.getEl(item.id);
2243 if (!item.checkReady ||
2246 (document && document.body)) {
2249 if (item.override) {
2250 if (item.override === true) {
2253 scope = item.override;
2256 item.fn.call(scope, item.obj);
2257 onAvailStack[i] = null;
2260 notAvail.push(item);
2265 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2269 this.startInterval();
2271 clearInterval(this._interval);
2272 this._interval = null;
2275 this.locked = false;
2282 purgeElement: function(el, recurse, eventName) {
2283 var elListeners = this.getListeners(el, eventName);
2285 for (var i = 0,len = elListeners.length; i < len; ++i) {
2286 var l = elListeners[i];
2287 this.removeListener(el, l.type, l.fn);
2291 if (recurse && el && el.childNodes) {
2292 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2293 this.purgeElement(el.childNodes[i], recurse, eventName);
2299 getListeners: function(el, eventName) {
2300 var results = [], searchLists;
2302 searchLists = [listeners, unloadListeners];
2303 } else if (eventName == "unload") {
2304 searchLists = [unloadListeners];
2306 searchLists = [listeners];
2309 for (var j = 0; j < searchLists.length; ++j) {
2310 var searchList = searchLists[j];
2311 if (searchList && searchList.length > 0) {
2312 for (var i = 0,len = searchList.length; i < len; ++i) {
2313 var l = searchList[i];
2314 if (l && l[this.EL] === el &&
2315 (!eventName || eventName === l[this.TYPE])) {
2320 adjust: l[this.ADJ_SCOPE],
2328 return (results.length) ? results : null;
2332 _unload: function(e) {
2334 var EU = Roo.lib.Event, i, j, l, len, index;
2336 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2337 l = unloadListeners[i];
2340 if (l[EU.ADJ_SCOPE]) {
2341 if (l[EU.ADJ_SCOPE] === true) {
2344 scope = l[EU.ADJ_SCOPE];
2347 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2348 unloadListeners[i] = null;
2354 unloadListeners = null;
2356 if (listeners && listeners.length > 0) {
2357 j = listeners.length;
2360 l = listeners[index];
2362 EU.removeListener(l[EU.EL], l[EU.TYPE],
2372 EU.doRemove(window, "unload", EU._unload);
2377 getScroll: function() {
2378 var dd = document.documentElement, db = document.body;
2379 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2380 return [dd.scrollTop, dd.scrollLeft];
2382 return [db.scrollTop, db.scrollLeft];
2389 doAdd: function () {
2390 if (window.addEventListener) {
2391 return function(el, eventName, fn, capture) {
2392 el.addEventListener(eventName, fn, (capture));
2394 } else if (window.attachEvent) {
2395 return function(el, eventName, fn, capture) {
2396 el.attachEvent("on" + eventName, fn);
2405 doRemove: function() {
2406 if (window.removeEventListener) {
2407 return function (el, eventName, fn, capture) {
2408 el.removeEventListener(eventName, fn, (capture));
2410 } else if (window.detachEvent) {
2411 return function (el, eventName, fn) {
2412 el.detachEvent("on" + eventName, fn);
2424 var E = Roo.lib.Event;
2425 E.on = E.addListener;
2426 E.un = E.removeListener;
2428 if (document && document.body) {
2431 E.doAdd(window, "load", E._load);
2433 E.doAdd(window, "unload", E._unload);
2434 E._tryPreloadAttach();
2438 * Portions of this file are based on pieces of Yahoo User Interface Library
2439 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2440 * YUI licensed under the BSD License:
2441 * http://developer.yahoo.net/yui/license.txt
2442 * <script type="text/javascript">
2449 request : function(method, uri, cb, data, options) {
2451 var hs = options.headers;
2454 if(hs.hasOwnProperty(h)){
2455 this.initHeader(h, hs[h], false);
2459 if(options.xmlData){
2460 this.initHeader('Content-Type', 'text/xml', false);
2462 data = options.xmlData;
2466 return this.asyncRequest(method, uri, cb, data);
2469 serializeForm : function(form) {
2470 if(typeof form == 'string') {
2471 form = (document.getElementById(form) || document.forms[form]);
2474 var el, name, val, disabled, data = '', hasSubmit = false;
2475 for (var i = 0; i < form.elements.length; i++) {
2476 el = form.elements[i];
2477 disabled = form.elements[i].disabled;
2478 name = form.elements[i].name;
2479 val = form.elements[i].value;
2481 if (!disabled && name){
2485 case 'select-multiple':
2486 for (var j = 0; j < el.options.length; j++) {
2487 if (el.options[j].selected) {
2489 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2492 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2500 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2513 if(hasSubmit == false) {
2514 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2519 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2524 data = data.substr(0, data.length - 1);
2532 useDefaultHeader:true,
2534 defaultPostHeader:'application/x-www-form-urlencoded',
2536 useDefaultXhrHeader:true,
2538 defaultXhrHeader:'XMLHttpRequest',
2540 hasDefaultHeaders:true,
2552 setProgId:function(id)
2554 this.activeX.unshift(id);
2557 setDefaultPostHeader:function(b)
2559 this.useDefaultHeader = b;
2562 setDefaultXhrHeader:function(b)
2564 this.useDefaultXhrHeader = b;
2567 setPollingInterval:function(i)
2569 if (typeof i == 'number' && isFinite(i)) {
2570 this.pollInterval = i;
2574 createXhrObject:function(transactionId)
2580 http = new XMLHttpRequest();
2582 obj = { conn:http, tId:transactionId };
2586 for (var i = 0; i < this.activeX.length; ++i) {
2590 http = new ActiveXObject(this.activeX[i]);
2592 obj = { conn:http, tId:transactionId };
2605 getConnectionObject:function()
2608 var tId = this.transactionId;
2612 o = this.createXhrObject(tId);
2614 this.transactionId++;
2625 asyncRequest:function(method, uri, callback, postData)
2627 var o = this.getConnectionObject();
2633 o.conn.open(method, uri, true);
2635 if (this.useDefaultXhrHeader) {
2636 if (!this.defaultHeaders['X-Requested-With']) {
2637 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2641 if(postData && this.useDefaultHeader){
2642 this.initHeader('Content-Type', this.defaultPostHeader);
2645 if (this.hasDefaultHeaders || this.hasHeaders) {
2649 this.handleReadyState(o, callback);
2650 o.conn.send(postData || null);
2656 handleReadyState:function(o, callback)
2660 if (callback && callback.timeout) {
2661 this.timeout[o.tId] = window.setTimeout(function() {
2662 oConn.abort(o, callback, true);
2663 }, callback.timeout);
2666 this.poll[o.tId] = window.setInterval(
2668 if (o.conn && o.conn.readyState == 4) {
2669 window.clearInterval(oConn.poll[o.tId]);
2670 delete oConn.poll[o.tId];
2672 if(callback && callback.timeout) {
2673 window.clearTimeout(oConn.timeout[o.tId]);
2674 delete oConn.timeout[o.tId];
2677 oConn.handleTransactionResponse(o, callback);
2680 , this.pollInterval);
2683 handleTransactionResponse:function(o, callback, isAbort)
2687 this.releaseObject(o);
2691 var httpStatus, responseObject;
2695 if (o.conn.status !== undefined && o.conn.status != 0) {
2696 httpStatus = o.conn.status;
2708 if (httpStatus >= 200 && httpStatus < 300) {
2709 responseObject = this.createResponseObject(o, callback.argument);
2710 if (callback.success) {
2711 if (!callback.scope) {
2712 callback.success(responseObject);
2717 callback.success.apply(callback.scope, [responseObject]);
2722 switch (httpStatus) {
2730 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2731 if (callback.failure) {
2732 if (!callback.scope) {
2733 callback.failure(responseObject);
2736 callback.failure.apply(callback.scope, [responseObject]);
2741 responseObject = this.createResponseObject(o, callback.argument);
2742 if (callback.failure) {
2743 if (!callback.scope) {
2744 callback.failure(responseObject);
2747 callback.failure.apply(callback.scope, [responseObject]);
2753 this.releaseObject(o);
2754 responseObject = null;
2757 createResponseObject:function(o, callbackArg)
2764 var headerStr = o.conn.getAllResponseHeaders();
2765 var header = headerStr.split('\n');
2766 for (var i = 0; i < header.length; i++) {
2767 var delimitPos = header[i].indexOf(':');
2768 if (delimitPos != -1) {
2769 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2777 obj.status = o.conn.status;
2778 obj.statusText = o.conn.statusText;
2779 obj.getResponseHeader = headerObj;
2780 obj.getAllResponseHeaders = headerStr;
2781 obj.responseText = o.conn.responseText;
2782 obj.responseXML = o.conn.responseXML;
2784 if (typeof callbackArg !== undefined) {
2785 obj.argument = callbackArg;
2791 createExceptionObject:function(tId, callbackArg, isAbort)
2794 var COMM_ERROR = 'communication failure';
2795 var ABORT_CODE = -1;
2796 var ABORT_ERROR = 'transaction aborted';
2802 obj.status = ABORT_CODE;
2803 obj.statusText = ABORT_ERROR;
2806 obj.status = COMM_CODE;
2807 obj.statusText = COMM_ERROR;
2811 obj.argument = callbackArg;
2817 initHeader:function(label, value, isDefault)
2819 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2821 if (headerObj[label] === undefined) {
2822 headerObj[label] = value;
2827 headerObj[label] = value + "," + headerObj[label];
2831 this.hasDefaultHeaders = true;
2834 this.hasHeaders = true;
2839 setHeader:function(o)
2841 if (this.hasDefaultHeaders) {
2842 for (var prop in this.defaultHeaders) {
2843 if (this.defaultHeaders.hasOwnProperty(prop)) {
2844 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2849 if (this.hasHeaders) {
2850 for (var prop in this.headers) {
2851 if (this.headers.hasOwnProperty(prop)) {
2852 o.conn.setRequestHeader(prop, this.headers[prop]);
2856 this.hasHeaders = false;
2860 resetDefaultHeaders:function() {
2861 delete this.defaultHeaders;
2862 this.defaultHeaders = {};
2863 this.hasDefaultHeaders = false;
2866 abort:function(o, callback, isTimeout)
2868 if(this.isCallInProgress(o)) {
2870 window.clearInterval(this.poll[o.tId]);
2871 delete this.poll[o.tId];
2873 delete this.timeout[o.tId];
2876 this.handleTransactionResponse(o, callback, true);
2886 isCallInProgress:function(o)
2889 return o.conn.readyState != 4 && o.conn.readyState != 0;
2898 releaseObject:function(o)
2907 'MSXML2.XMLHTTP.3.0',
2915 * Portions of this file are based on pieces of Yahoo User Interface Library
2916 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2917 * YUI licensed under the BSD License:
2918 * http://developer.yahoo.net/yui/license.txt
2919 * <script type="text/javascript">
2923 Roo.lib.Region = function(t, r, b, l) {
2933 Roo.lib.Region.prototype = {
2934 contains : function(region) {
2935 return ( region.left >= this.left &&
2936 region.right <= this.right &&
2937 region.top >= this.top &&
2938 region.bottom <= this.bottom );
2942 getArea : function() {
2943 return ( (this.bottom - this.top) * (this.right - this.left) );
2946 intersect : function(region) {
2947 var t = Math.max(this.top, region.top);
2948 var r = Math.min(this.right, region.right);
2949 var b = Math.min(this.bottom, region.bottom);
2950 var l = Math.max(this.left, region.left);
2952 if (b >= t && r >= l) {
2953 return new Roo.lib.Region(t, r, b, l);
2958 union : function(region) {
2959 var t = Math.min(this.top, region.top);
2960 var r = Math.max(this.right, region.right);
2961 var b = Math.max(this.bottom, region.bottom);
2962 var l = Math.min(this.left, region.left);
2964 return new Roo.lib.Region(t, r, b, l);
2967 adjust : function(t, l, b, r) {
2976 Roo.lib.Region.getRegion = function(el) {
2977 var p = Roo.lib.Dom.getXY(el);
2980 var r = p[0] + el.offsetWidth;
2981 var b = p[1] + el.offsetHeight;
2984 return new Roo.lib.Region(t, r, b, l);
2987 * Portions of this file are based on pieces of Yahoo User Interface Library
2988 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2989 * YUI licensed under the BSD License:
2990 * http://developer.yahoo.net/yui/license.txt
2991 * <script type="text/javascript">
2994 //@@dep Roo.lib.Region
2997 Roo.lib.Point = function(x, y) {
2998 if (x instanceof Array) {
3002 this.x = this.right = this.left = this[0] = x;
3003 this.y = this.top = this.bottom = this[1] = y;
3006 Roo.lib.Point.prototype = new Roo.lib.Region();
3008 * Portions of this file are based on pieces of Yahoo User Interface Library
3009 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010 * YUI licensed under the BSD License:
3011 * http://developer.yahoo.net/yui/license.txt
3012 * <script type="text/javascript">
3019 scroll : function(el, args, duration, easing, cb, scope) {
3020 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3023 motion : function(el, args, duration, easing, cb, scope) {
3024 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3027 color : function(el, args, duration, easing, cb, scope) {
3028 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3031 run : function(el, args, duration, easing, cb, scope, type) {
3032 type = type || Roo.lib.AnimBase;
3033 if (typeof easing == "string") {
3034 easing = Roo.lib.Easing[easing];
3036 var anim = new type(el, args, duration, easing);
3037 anim.animateX(function() {
3038 Roo.callback(cb, scope);
3044 * Portions of this file are based on pieces of Yahoo User Interface Library
3045 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3046 * YUI licensed under the BSD License:
3047 * http://developer.yahoo.net/yui/license.txt
3048 * <script type="text/javascript">
3056 if (!libFlyweight) {
3057 libFlyweight = new Roo.Element.Flyweight();
3059 libFlyweight.dom = el;
3060 return libFlyweight;
3063 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3067 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3069 this.init(el, attributes, duration, method);
3073 Roo.lib.AnimBase.fly = fly;
3077 Roo.lib.AnimBase.prototype = {
3079 toString: function() {
3080 var el = this.getEl();
3081 var id = el.id || el.tagName;
3082 return ("Anim " + id);
3086 noNegatives: /width|height|opacity|padding/i,
3087 offsetAttribute: /^((width|height)|(top|left))$/,
3088 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3089 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3093 doMethod: function(attr, start, end) {
3094 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3098 setAttribute: function(attr, val, unit) {
3099 if (this.patterns.noNegatives.test(attr)) {
3100 val = (val > 0) ? val : 0;
3103 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3107 getAttribute: function(attr) {
3108 var el = this.getEl();
3109 var val = fly(el).getStyle(attr);
3111 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3112 return parseFloat(val);
3115 var a = this.patterns.offsetAttribute.exec(attr) || [];
3116 var pos = !!( a[3] );
3117 var box = !!( a[2] );
3120 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3121 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3130 getDefaultUnit: function(attr) {
3131 if (this.patterns.defaultUnit.test(attr)) {
3138 animateX : function(callback, scope) {
3139 var f = function() {
3140 this.onComplete.removeListener(f);
3141 if (typeof callback == "function") {
3142 callback.call(scope || this, this);
3145 this.onComplete.addListener(f, this);
3150 setRuntimeAttribute: function(attr) {
3153 var attributes = this.attributes;
3155 this.runtimeAttributes[attr] = {};
3157 var isset = function(prop) {
3158 return (typeof prop !== 'undefined');
3161 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3165 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3168 if (isset(attributes[attr]['to'])) {
3169 end = attributes[attr]['to'];
3170 } else if (isset(attributes[attr]['by'])) {
3171 if (start.constructor == Array) {
3173 for (var i = 0, len = start.length; i < len; ++i) {
3174 end[i] = start[i] + attributes[attr]['by'][i];
3177 end = start + attributes[attr]['by'];
3181 this.runtimeAttributes[attr].start = start;
3182 this.runtimeAttributes[attr].end = end;
3185 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3189 init: function(el, attributes, duration, method) {
3191 var isAnimated = false;
3194 var startTime = null;
3197 var actualFrames = 0;
3200 el = Roo.getDom(el);
3203 this.attributes = attributes || {};
3206 this.duration = duration || 1;
3209 this.method = method || Roo.lib.Easing.easeNone;
3212 this.useSeconds = true;
3215 this.currentFrame = 0;
3218 this.totalFrames = Roo.lib.AnimMgr.fps;
3221 this.getEl = function() {
3226 this.isAnimated = function() {
3231 this.getStartTime = function() {
3235 this.runtimeAttributes = {};
3238 this.animate = function() {
3239 if (this.isAnimated()) {
3243 this.currentFrame = 0;
3245 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3247 Roo.lib.AnimMgr.registerElement(this);
3251 this.stop = function(finish) {
3253 this.currentFrame = this.totalFrames;
3254 this._onTween.fire();
3256 Roo.lib.AnimMgr.stop(this);
3259 var onStart = function() {
3260 this.onStart.fire();
3262 this.runtimeAttributes = {};
3263 for (var attr in this.attributes) {
3264 this.setRuntimeAttribute(attr);
3269 startTime = new Date();
3273 var onTween = function() {
3275 duration: new Date() - this.getStartTime(),
3276 currentFrame: this.currentFrame
3279 data.toString = function() {
3281 'duration: ' + data.duration +
3282 ', currentFrame: ' + data.currentFrame
3286 this.onTween.fire(data);
3288 var runtimeAttributes = this.runtimeAttributes;
3290 for (var attr in runtimeAttributes) {
3291 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3297 var onComplete = function() {
3298 var actual_duration = (new Date() - startTime) / 1000 ;
3301 duration: actual_duration,
3302 frames: actualFrames,
3303 fps: actualFrames / actual_duration
3306 data.toString = function() {
3308 'duration: ' + data.duration +
3309 ', frames: ' + data.frames +
3310 ', fps: ' + data.fps
3316 this.onComplete.fire(data);
3320 this._onStart = new Roo.util.Event(this);
3321 this.onStart = new Roo.util.Event(this);
3322 this.onTween = new Roo.util.Event(this);
3323 this._onTween = new Roo.util.Event(this);
3324 this.onComplete = new Roo.util.Event(this);
3325 this._onComplete = new Roo.util.Event(this);
3326 this._onStart.addListener(onStart);
3327 this._onTween.addListener(onTween);
3328 this._onComplete.addListener(onComplete);
3333 * Portions of this file are based on pieces of Yahoo User Interface Library
3334 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3335 * YUI licensed under the BSD License:
3336 * http://developer.yahoo.net/yui/license.txt
3337 * <script type="text/javascript">
3341 Roo.lib.AnimMgr = new function() {
3358 this.registerElement = function(tween) {
3359 queue[queue.length] = tween;
3361 tween._onStart.fire();
3366 this.unRegister = function(tween, index) {
3367 tween._onComplete.fire();
3368 index = index || getIndex(tween);
3370 queue.splice(index, 1);
3374 if (tweenCount <= 0) {
3380 this.start = function() {
3381 if (thread === null) {
3382 thread = setInterval(this.run, this.delay);
3387 this.stop = function(tween) {
3389 clearInterval(thread);
3391 for (var i = 0, len = queue.length; i < len; ++i) {
3392 if (queue[0].isAnimated()) {
3393 this.unRegister(queue[0], 0);
3402 this.unRegister(tween);
3407 this.run = function() {
3408 for (var i = 0, len = queue.length; i < len; ++i) {
3409 var tween = queue[i];
3410 if (!tween || !tween.isAnimated()) {
3414 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3416 tween.currentFrame += 1;
3418 if (tween.useSeconds) {
3419 correctFrame(tween);
3421 tween._onTween.fire();
3424 Roo.lib.AnimMgr.stop(tween, i);
3429 var getIndex = function(anim) {
3430 for (var i = 0, len = queue.length; i < len; ++i) {
3431 if (queue[i] == anim) {
3439 var correctFrame = function(tween) {
3440 var frames = tween.totalFrames;
3441 var frame = tween.currentFrame;
3442 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3443 var elapsed = (new Date() - tween.getStartTime());
3446 if (elapsed < tween.duration * 1000) {
3447 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3449 tweak = frames - (frame + 1);
3451 if (tweak > 0 && isFinite(tweak)) {
3452 if (tween.currentFrame + tweak >= frames) {
3453 tweak = frames - (frame + 1);
3456 tween.currentFrame += tweak;
3460 * Portions of this file are based on pieces of Yahoo User Interface Library
3461 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3462 * YUI licensed under the BSD License:
3463 * http://developer.yahoo.net/yui/license.txt
3464 * <script type="text/javascript">
3467 Roo.lib.Bezier = new function() {
3469 this.getPosition = function(points, t) {
3470 var n = points.length;
3473 for (var i = 0; i < n; ++i) {
3474 tmp[i] = [points[i][0], points[i][1]];
3477 for (var j = 1; j < n; ++j) {
3478 for (i = 0; i < n - j; ++i) {
3479 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3480 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3484 return [ tmp[0][0], tmp[0][1] ];
3488 * Portions of this file are based on pieces of Yahoo User Interface Library
3489 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3490 * YUI licensed under the BSD License:
3491 * http://developer.yahoo.net/yui/license.txt
3492 * <script type="text/javascript">
3497 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3498 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3501 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3503 var fly = Roo.lib.AnimBase.fly;
3505 var superclass = Y.ColorAnim.superclass;
3506 var proto = Y.ColorAnim.prototype;
3508 proto.toString = function() {
3509 var el = this.getEl();
3510 var id = el.id || el.tagName;
3511 return ("ColorAnim " + id);
3514 proto.patterns.color = /color$/i;
3515 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3516 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3517 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3518 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3521 proto.parseColor = function(s) {
3522 if (s.length == 3) {
3526 var c = this.patterns.hex.exec(s);
3527 if (c && c.length == 4) {
3528 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3531 c = this.patterns.rgb.exec(s);
3532 if (c && c.length == 4) {
3533 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3536 c = this.patterns.hex3.exec(s);
3537 if (c && c.length == 4) {
3538 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3543 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3544 proto.getAttribute = function(attr) {
3545 var el = this.getEl();
3546 if (this.patterns.color.test(attr)) {
3547 var val = fly(el).getStyle(attr);
3549 if (this.patterns.transparent.test(val)) {
3550 var parent = el.parentNode;
3551 val = fly(parent).getStyle(attr);
3553 while (parent && this.patterns.transparent.test(val)) {
3554 parent = parent.parentNode;
3555 val = fly(parent).getStyle(attr);
3556 if (parent.tagName.toUpperCase() == 'HTML') {
3562 val = superclass.getAttribute.call(this, attr);
3567 proto.getAttribute = function(attr) {
3568 var el = this.getEl();
3569 if (this.patterns.color.test(attr)) {
3570 var val = fly(el).getStyle(attr);
3572 if (this.patterns.transparent.test(val)) {
3573 var parent = el.parentNode;
3574 val = fly(parent).getStyle(attr);
3576 while (parent && this.patterns.transparent.test(val)) {
3577 parent = parent.parentNode;
3578 val = fly(parent).getStyle(attr);
3579 if (parent.tagName.toUpperCase() == 'HTML') {
3585 val = superclass.getAttribute.call(this, attr);
3591 proto.doMethod = function(attr, start, end) {
3594 if (this.patterns.color.test(attr)) {
3596 for (var i = 0, len = start.length; i < len; ++i) {
3597 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3600 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3603 val = superclass.doMethod.call(this, attr, start, end);
3609 proto.setRuntimeAttribute = function(attr) {
3610 superclass.setRuntimeAttribute.call(this, attr);
3612 if (this.patterns.color.test(attr)) {
3613 var attributes = this.attributes;
3614 var start = this.parseColor(this.runtimeAttributes[attr].start);
3615 var end = this.parseColor(this.runtimeAttributes[attr].end);
3617 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3618 end = this.parseColor(attributes[attr].by);
3620 for (var i = 0, len = start.length; i < len; ++i) {
3621 end[i] = start[i] + end[i];
3625 this.runtimeAttributes[attr].start = start;
3626 this.runtimeAttributes[attr].end = end;
3632 * Portions of this file are based on pieces of Yahoo User Interface Library
3633 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3634 * YUI licensed under the BSD License:
3635 * http://developer.yahoo.net/yui/license.txt
3636 * <script type="text/javascript">
3642 easeNone: function (t, b, c, d) {
3643 return c * t / d + b;
3647 easeIn: function (t, b, c, d) {
3648 return c * (t /= d) * t + b;
3652 easeOut: function (t, b, c, d) {
3653 return -c * (t /= d) * (t - 2) + b;
3657 easeBoth: function (t, b, c, d) {
3658 if ((t /= d / 2) < 1) {
3659 return c / 2 * t * t + b;
3662 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3666 easeInStrong: function (t, b, c, d) {
3667 return c * (t /= d) * t * t * t + b;
3671 easeOutStrong: function (t, b, c, d) {
3672 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3676 easeBothStrong: function (t, b, c, d) {
3677 if ((t /= d / 2) < 1) {
3678 return c / 2 * t * t * t * t + b;
3681 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3686 elasticIn: function (t, b, c, d, a, p) {
3690 if ((t /= d) == 1) {
3697 if (!a || a < Math.abs(c)) {
3702 var s = p / (2 * Math.PI) * Math.asin(c / a);
3705 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3709 elasticOut: function (t, b, c, d, a, p) {
3713 if ((t /= d) == 1) {
3720 if (!a || a < Math.abs(c)) {
3725 var s = p / (2 * Math.PI) * Math.asin(c / a);
3728 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3732 elasticBoth: function (t, b, c, d, a, p) {
3737 if ((t /= d / 2) == 2) {
3745 if (!a || a < Math.abs(c)) {
3750 var s = p / (2 * Math.PI) * Math.asin(c / a);
3754 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3755 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3757 return a * Math.pow(2, -10 * (t -= 1)) *
3758 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3763 backIn: function (t, b, c, d, s) {
3764 if (typeof s == 'undefined') {
3767 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3771 backOut: function (t, b, c, d, s) {
3772 if (typeof s == 'undefined') {
3775 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3779 backBoth: function (t, b, c, d, s) {
3780 if (typeof s == 'undefined') {
3784 if ((t /= d / 2 ) < 1) {
3785 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3787 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3791 bounceIn: function (t, b, c, d) {
3792 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3796 bounceOut: function (t, b, c, d) {
3797 if ((t /= d) < (1 / 2.75)) {
3798 return c * (7.5625 * t * t) + b;
3799 } else if (t < (2 / 2.75)) {
3800 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3801 } else if (t < (2.5 / 2.75)) {
3802 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3804 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3808 bounceBoth: function (t, b, c, d) {
3810 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3812 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3815 * Portions of this file are based on pieces of Yahoo User Interface Library
3816 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3817 * YUI licensed under the BSD License:
3818 * http://developer.yahoo.net/yui/license.txt
3819 * <script type="text/javascript">
3823 Roo.lib.Motion = function(el, attributes, duration, method) {
3825 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3829 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3833 var superclass = Y.Motion.superclass;
3834 var proto = Y.Motion.prototype;
3836 proto.toString = function() {
3837 var el = this.getEl();
3838 var id = el.id || el.tagName;
3839 return ("Motion " + id);
3842 proto.patterns.points = /^points$/i;
3844 proto.setAttribute = function(attr, val, unit) {
3845 if (this.patterns.points.test(attr)) {
3846 unit = unit || 'px';
3847 superclass.setAttribute.call(this, 'left', val[0], unit);
3848 superclass.setAttribute.call(this, 'top', val[1], unit);
3850 superclass.setAttribute.call(this, attr, val, unit);
3854 proto.getAttribute = function(attr) {
3855 if (this.patterns.points.test(attr)) {
3857 superclass.getAttribute.call(this, 'left'),
3858 superclass.getAttribute.call(this, 'top')
3861 val = superclass.getAttribute.call(this, attr);
3867 proto.doMethod = function(attr, start, end) {
3870 if (this.patterns.points.test(attr)) {
3871 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3872 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3874 val = superclass.doMethod.call(this, attr, start, end);
3879 proto.setRuntimeAttribute = function(attr) {
3880 if (this.patterns.points.test(attr)) {
3881 var el = this.getEl();
3882 var attributes = this.attributes;
3884 var control = attributes['points']['control'] || [];
3888 if (control.length > 0 && !(control[0] instanceof Array)) {
3889 control = [control];
3892 for (i = 0,len = control.length; i < len; ++i) {
3893 tmp[i] = control[i];
3898 Roo.fly(el).position();
3900 if (isset(attributes['points']['from'])) {
3901 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3904 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3907 start = this.getAttribute('points');
3910 if (isset(attributes['points']['to'])) {
3911 end = translateValues.call(this, attributes['points']['to'], start);
3913 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3914 for (i = 0,len = control.length; i < len; ++i) {
3915 control[i] = translateValues.call(this, control[i], start);
3919 } else if (isset(attributes['points']['by'])) {
3920 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3922 for (i = 0,len = control.length; i < len; ++i) {
3923 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3927 this.runtimeAttributes[attr] = [start];
3929 if (control.length > 0) {
3930 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3933 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3936 superclass.setRuntimeAttribute.call(this, attr);
3940 var translateValues = function(val, start) {
3941 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3942 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3947 var isset = function(prop) {
3948 return (typeof prop !== 'undefined');
3952 * Portions of this file are based on pieces of Yahoo User Interface Library
3953 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3954 * YUI licensed under the BSD License:
3955 * http://developer.yahoo.net/yui/license.txt
3956 * <script type="text/javascript">
3960 Roo.lib.Scroll = function(el, attributes, duration, method) {
3962 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3966 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3970 var superclass = Y.Scroll.superclass;
3971 var proto = Y.Scroll.prototype;
3973 proto.toString = function() {
3974 var el = this.getEl();
3975 var id = el.id || el.tagName;
3976 return ("Scroll " + id);
3979 proto.doMethod = function(attr, start, end) {
3982 if (attr == 'scroll') {
3984 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3985 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3989 val = superclass.doMethod.call(this, attr, start, end);
3994 proto.getAttribute = function(attr) {
3996 var el = this.getEl();
3998 if (attr == 'scroll') {
3999 val = [ el.scrollLeft, el.scrollTop ];
4001 val = superclass.getAttribute.call(this, attr);
4007 proto.setAttribute = function(attr, val, unit) {
4008 var el = this.getEl();
4010 if (attr == 'scroll') {
4011 el.scrollLeft = val[0];
4012 el.scrollTop = val[1];
4014 superclass.setAttribute.call(this, attr, val, unit);
4020 * Ext JS Library 1.1.1
4021 * Copyright(c) 2006-2007, Ext JS, LLC.
4023 * Originally Released Under LGPL - original licence link has changed is not relivant.
4026 * <script type="text/javascript">
4031 * @class Roo.DomHelper
4032 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4033 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4036 Roo.DomHelper = function(){
4037 var tempTableEl = null;
4038 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4039 var tableRe = /^table|tbody|tr|td$/i;
4041 // build as innerHTML where available
4043 var createHtml = function(o){
4044 if(typeof o == 'string'){
4053 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4054 if(attr == "style"){
4056 if(typeof s == "function"){
4059 if(typeof s == "string"){
4060 b += ' style="' + s + '"';
4061 }else if(typeof s == "object"){
4064 if(typeof s[key] != "function"){
4065 b += key + ":" + s[key] + ";";
4072 b += ' class="' + o["cls"] + '"';
4073 }else if(attr == "htmlFor"){
4074 b += ' for="' + o["htmlFor"] + '"';
4076 b += " " + attr + '="' + o[attr] + '"';
4080 if(emptyTags.test(o.tag)){
4084 var cn = o.children || o.cn;
4086 //http://bugs.kde.org/show_bug.cgi?id=71506
4087 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4088 for(var i = 0, len = cn.length; i < len; i++) {
4089 b += createHtml(cn[i], b);
4092 b += createHtml(cn, b);
4098 b += "</" + o.tag + ">";
4105 var createDom = function(o, parentNode){
4107 // defininition craeted..
4109 if (o.ns && o.ns != 'html') {
4111 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4112 xmlns[o.ns] = o.xmlns;
4115 if (typeof(xmlns[o.ns]) == 'undefined') {
4116 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4122 if (typeof(o) == 'string') {
4123 return parentNode.appendChild(document.createTextNode(o));
4125 o.tag = o.tag || div;
4126 if (o.ns && Roo.isIE) {
4128 o.tag = o.ns + ':' + o.tag;
4131 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4132 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4135 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4136 attr == "style" || typeof o[attr] == "function") continue;
4138 if(attr=="cls" && Roo.isIE){
4139 el.className = o["cls"];
4141 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4142 else el[attr] = o[attr];
4145 Roo.DomHelper.applyStyles(el, o.style);
4146 var cn = o.children || o.cn;
4148 //http://bugs.kde.org/show_bug.cgi?id=71506
4149 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4150 for(var i = 0, len = cn.length; i < len; i++) {
4151 createDom(cn[i], el);
4158 el.innerHTML = o.html;
4161 parentNode.appendChild(el);
4166 var ieTable = function(depth, s, h, e){
4167 tempTableEl.innerHTML = [s, h, e].join('');
4168 var i = -1, el = tempTableEl;
4175 // kill repeat to save bytes
4179 tbe = '</tbody>'+te,
4185 * Nasty code for IE's broken table implementation
4187 var insertIntoTable = function(tag, where, el, html){
4189 tempTableEl = document.createElement('div');
4194 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4197 if(where == 'beforebegin'){
4201 before = el.nextSibling;
4204 node = ieTable(4, trs, html, tre);
4206 else if(tag == 'tr'){
4207 if(where == 'beforebegin'){
4210 node = ieTable(3, tbs, html, tbe);
4211 } else if(where == 'afterend'){
4212 before = el.nextSibling;
4214 node = ieTable(3, tbs, html, tbe);
4215 } else{ // INTO a TR
4216 if(where == 'afterbegin'){
4217 before = el.firstChild;
4219 node = ieTable(4, trs, html, tre);
4221 } else if(tag == 'tbody'){
4222 if(where == 'beforebegin'){
4225 node = ieTable(2, ts, html, te);
4226 } else if(where == 'afterend'){
4227 before = el.nextSibling;
4229 node = ieTable(2, ts, html, te);
4231 if(where == 'afterbegin'){
4232 before = el.firstChild;
4234 node = ieTable(3, tbs, html, tbe);
4237 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4240 if(where == 'afterbegin'){
4241 before = el.firstChild;
4243 node = ieTable(2, ts, html, te);
4245 el.insertBefore(node, before);
4250 /** True to force the use of DOM instead of html fragments @type Boolean */
4254 * Returns the markup for the passed Element(s) config
4255 * @param {Object} o The Dom object spec (and children)
4258 markup : function(o){
4259 return createHtml(o);
4263 * Applies a style specification to an element
4264 * @param {String/HTMLElement} el The element to apply styles to
4265 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4266 * a function which returns such a specification.
4268 applyStyles : function(el, styles){
4271 if(typeof styles == "string"){
4272 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4274 while ((matches = re.exec(styles)) != null){
4275 el.setStyle(matches[1], matches[2]);
4277 }else if (typeof styles == "object"){
4278 for (var style in styles){
4279 el.setStyle(style, styles[style]);
4281 }else if (typeof styles == "function"){
4282 Roo.DomHelper.applyStyles(el, styles.call());
4288 * Inserts an HTML fragment into the Dom
4289 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4290 * @param {HTMLElement} el The context element
4291 * @param {String} html The HTML fragmenet
4292 * @return {HTMLElement} The new node
4294 insertHtml : function(where, el, html){
4295 where = where.toLowerCase();
4296 if(el.insertAdjacentHTML){
4297 if(tableRe.test(el.tagName)){
4299 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4305 el.insertAdjacentHTML('BeforeBegin', html);
4306 return el.previousSibling;
4308 el.insertAdjacentHTML('AfterBegin', html);
4309 return el.firstChild;
4311 el.insertAdjacentHTML('BeforeEnd', html);
4312 return el.lastChild;
4314 el.insertAdjacentHTML('AfterEnd', html);
4315 return el.nextSibling;
4317 throw 'Illegal insertion point -> "' + where + '"';
4319 var range = el.ownerDocument.createRange();
4323 range.setStartBefore(el);
4324 frag = range.createContextualFragment(html);
4325 el.parentNode.insertBefore(frag, el);
4326 return el.previousSibling;
4329 range.setStartBefore(el.firstChild);
4330 frag = range.createContextualFragment(html);
4331 el.insertBefore(frag, el.firstChild);
4332 return el.firstChild;
4334 el.innerHTML = html;
4335 return el.firstChild;
4339 range.setStartAfter(el.lastChild);
4340 frag = range.createContextualFragment(html);
4341 el.appendChild(frag);
4342 return el.lastChild;
4344 el.innerHTML = html;
4345 return el.lastChild;
4348 range.setStartAfter(el);
4349 frag = range.createContextualFragment(html);
4350 el.parentNode.insertBefore(frag, el.nextSibling);
4351 return el.nextSibling;
4353 throw 'Illegal insertion point -> "' + where + '"';
4357 * Creates new Dom element(s) and inserts them before el
4358 * @param {String/HTMLElement/Element} el The context element
4359 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4360 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4361 * @return {HTMLElement/Roo.Element} The new node
4363 insertBefore : function(el, o, returnElement){
4364 return this.doInsert(el, o, returnElement, "beforeBegin");
4368 * Creates new Dom element(s) and inserts them after el
4369 * @param {String/HTMLElement/Element} el The context element
4370 * @param {Object} o The Dom object spec (and children)
4371 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4372 * @return {HTMLElement/Roo.Element} The new node
4374 insertAfter : function(el, o, returnElement){
4375 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4379 * Creates new Dom element(s) and inserts them as the first child of el
4380 * @param {String/HTMLElement/Element} el The context element
4381 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4382 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4383 * @return {HTMLElement/Roo.Element} The new node
4385 insertFirst : function(el, o, returnElement){
4386 return this.doInsert(el, o, returnElement, "afterBegin");
4390 doInsert : function(el, o, returnElement, pos, sibling){
4391 el = Roo.getDom(el);
4393 if(this.useDom || o.ns){
4394 newNode = createDom(o, null);
4395 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4397 var html = createHtml(o);
4398 newNode = this.insertHtml(pos, el, html);
4400 return returnElement ? Roo.get(newNode, true) : newNode;
4404 * Creates new Dom element(s) and appends them to el
4405 * @param {String/HTMLElement/Element} el The context element
4406 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4407 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4408 * @return {HTMLElement/Roo.Element} The new node
4410 append : function(el, o, returnElement){
4411 el = Roo.getDom(el);
4413 if(this.useDom || o.ns){
4414 newNode = createDom(o, null);
4415 el.appendChild(newNode);
4417 var html = createHtml(o);
4418 newNode = this.insertHtml("beforeEnd", el, html);
4420 return returnElement ? Roo.get(newNode, true) : newNode;
4424 * Creates new Dom element(s) and overwrites the contents of el with them
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 overwrite : function(el, o, returnElement){
4431 el = Roo.getDom(el);
4434 while (el.childNodes.length) {
4435 el.removeChild(el.firstChild);
4439 el.innerHTML = createHtml(o);
4442 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4446 * Creates a new Roo.DomHelper.Template from the Dom object spec
4447 * @param {Object} o The Dom object spec (and children)
4448 * @return {Roo.DomHelper.Template} The new template
4450 createTemplate : function(o){
4451 var html = createHtml(o);
4452 return new Roo.Template(html);
4458 * Ext JS Library 1.1.1
4459 * Copyright(c) 2006-2007, Ext JS, LLC.
4461 * Originally Released Under LGPL - original licence link has changed is not relivant.
4464 * <script type="text/javascript">
4468 * @class Roo.Template
4469 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4470 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4473 var t = new Roo.Template({
4474 html : '<div name="{id}">' +
4475 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4477 myformat: function (value, allValues) {
4478 return 'XX' + value;
4481 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4483 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4485 * @param {Object} cfg - Configuration object.
4487 Roo.Template = function(cfg){
4489 if(cfg instanceof Array){
4491 }else if(arguments.length > 1){
4492 cfg = Array.prototype.join.call(arguments, "");
4496 if (typeof(cfg) == 'object') {
4505 Roo.Template.prototype = {
4508 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4512 * Returns an HTML fragment of this template with the specified values applied.
4513 * @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'})
4514 * @return {String} The HTML fragment
4516 applyTemplate : function(values){
4520 return this.compiled(values);
4522 var useF = this.disableFormats !== true;
4523 var fm = Roo.util.Format, tpl = this;
4524 var fn = function(m, name, format, args){
4526 if(format.substr(0, 5) == "this."){
4527 return tpl.call(format.substr(5), values[name], values);
4530 // quoted values are required for strings in compiled templates,
4531 // but for non compiled we need to strip them
4532 // quoted reversed for jsmin
4533 var re = /^\s*['"](.*)["']\s*$/;
4534 args = args.split(',');
4535 for(var i = 0, len = args.length; i < len; i++){
4536 args[i] = args[i].replace(re, "$1");
4538 args = [values[name]].concat(args);
4540 args = [values[name]];
4542 return fm[format].apply(fm, args);
4545 return values[name] !== undefined ? values[name] : "";
4548 return this.html.replace(this.re, fn);
4557 * Sets the HTML used as the template and optionally compiles it.
4558 * @param {String} html
4559 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4560 * @return {Roo.Template} this
4562 set : function(html, compile){
4564 this.compiled = null;
4572 * True to disable format functions (defaults to false)
4575 disableFormats : false,
4578 * The regular expression used to match template variables
4582 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4585 * Compiles the template into an internal function, eliminating the RegEx overhead.
4586 * @return {Roo.Template} this
4588 compile : function(){
4589 var fm = Roo.util.Format;
4590 var useF = this.disableFormats !== true;
4591 var sep = Roo.isGecko ? "+" : ",";
4592 var fn = function(m, name, format, args){
4594 args = args ? ',' + args : "";
4595 if(format.substr(0, 5) != "this."){
4596 format = "fm." + format + '(';
4598 format = 'this.call("'+ format.substr(5) + '", ';
4602 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4604 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4607 // branched to use + in gecko and [].join() in others
4609 body = "this.compiled = function(values){ return '" +
4610 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4613 body = ["this.compiled = function(values){ return ['"];
4614 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4615 body.push("'].join('');};");
4616 body = body.join('');
4626 // private function used to call members
4627 call : function(fnName, value, allValues){
4628 return this[fnName](value, allValues);
4632 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4633 * @param {String/HTMLElement/Roo.Element} el The context element
4634 * @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'})
4635 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4636 * @return {HTMLElement/Roo.Element} The new node or Element
4638 insertFirst: function(el, values, returnElement){
4639 return this.doInsert('afterBegin', el, values, returnElement);
4643 * Applies the supplied values to the template and inserts the new node(s) before el.
4644 * @param {String/HTMLElement/Roo.Element} el The context element
4645 * @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'})
4646 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4647 * @return {HTMLElement/Roo.Element} The new node or Element
4649 insertBefore: function(el, values, returnElement){
4650 return this.doInsert('beforeBegin', el, values, returnElement);
4654 * Applies the supplied values to the template and inserts the new node(s) after el.
4655 * @param {String/HTMLElement/Roo.Element} el The context element
4656 * @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'})
4657 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4658 * @return {HTMLElement/Roo.Element} The new node or Element
4660 insertAfter : function(el, values, returnElement){
4661 return this.doInsert('afterEnd', el, values, returnElement);
4665 * Applies the supplied values to the template and appends the new node(s) to el.
4666 * @param {String/HTMLElement/Roo.Element} el The context element
4667 * @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'})
4668 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4669 * @return {HTMLElement/Roo.Element} The new node or Element
4671 append : function(el, values, returnElement){
4672 return this.doInsert('beforeEnd', el, values, returnElement);
4675 doInsert : function(where, el, values, returnEl){
4676 el = Roo.getDom(el);
4677 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4678 return returnEl ? Roo.get(newNode, true) : newNode;
4682 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4683 * @param {String/HTMLElement/Roo.Element} el The context element
4684 * @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'})
4685 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4686 * @return {HTMLElement/Roo.Element} The new node or Element
4688 overwrite : function(el, values, returnElement){
4689 el = Roo.getDom(el);
4690 el.innerHTML = this.applyTemplate(values);
4691 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4695 * Alias for {@link #applyTemplate}
4698 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4701 Roo.DomHelper.Template = Roo.Template;
4704 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4705 * @param {String/HTMLElement} el A DOM element or its id
4706 * @returns {Roo.Template} The created template
4709 Roo.Template.from = function(el){
4710 el = Roo.getDom(el);
4711 return new Roo.Template(el.value || el.innerHTML);
4714 * Ext JS Library 1.1.1
4715 * Copyright(c) 2006-2007, Ext JS, LLC.
4717 * Originally Released Under LGPL - original licence link has changed is not relivant.
4720 * <script type="text/javascript">
4725 * This is code is also distributed under MIT license for use
4726 * with jQuery and prototype JavaScript libraries.
4729 * @class Roo.DomQuery
4730 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).
4732 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>
4735 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.
4737 <h4>Element Selectors:</h4>
4739 <li> <b>*</b> any element</li>
4740 <li> <b>E</b> an element with the tag E</li>
4741 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4742 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4743 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4744 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4746 <h4>Attribute Selectors:</h4>
4747 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4749 <li> <b>E[foo]</b> has an attribute "foo"</li>
4750 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4751 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4752 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4753 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4754 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4755 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4757 <h4>Pseudo Classes:</h4>
4759 <li> <b>E:first-child</b> E is the first child of its parent</li>
4760 <li> <b>E:last-child</b> E is the last child of its parent</li>
4761 <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>
4762 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4763 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4764 <li> <b>E:only-child</b> E is the only child of its parent</li>
4765 <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>
4766 <li> <b>E:first</b> the first E in the resultset</li>
4767 <li> <b>E:last</b> the last E in the resultset</li>
4768 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4769 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4770 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4771 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4772 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4773 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4774 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4775 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4776 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4778 <h4>CSS Value Selectors:</h4>
4780 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4781 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4782 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4783 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4784 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4785 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4789 Roo.DomQuery = function(){
4790 var cache = {}, simpleCache = {}, valueCache = {};
4791 var nonSpace = /\S/;
4792 var trimRe = /^\s+|\s+$/g;
4793 var tplRe = /\{(\d+)\}/g;
4794 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4795 var tagTokenRe = /^(#)?([\w-\*]+)/;
4796 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4798 function child(p, index){
4800 var n = p.firstChild;
4802 if(n.nodeType == 1){
4813 while((n = n.nextSibling) && n.nodeType != 1);
4818 while((n = n.previousSibling) && n.nodeType != 1);
4822 function children(d){
4823 var n = d.firstChild, ni = -1;
4825 var nx = n.nextSibling;
4826 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4836 function byClassName(c, a, v){
4840 var r = [], ri = -1, cn;
4841 for(var i = 0, ci; ci = c[i]; i++){
4842 if((' '+ci.className+' ').indexOf(v) != -1){
4849 function attrValue(n, attr){
4850 if(!n.tagName && typeof n.length != "undefined"){
4859 if(attr == "class" || attr == "className"){
4862 return n.getAttribute(attr) || n[attr];
4866 function getNodes(ns, mode, tagName){
4867 var result = [], ri = -1, cs;
4871 tagName = tagName || "*";
4872 if(typeof ns.getElementsByTagName != "undefined"){
4876 for(var i = 0, ni; ni = ns[i]; i++){
4877 cs = ni.getElementsByTagName(tagName);
4878 for(var j = 0, ci; ci = cs[j]; j++){
4882 }else if(mode == "/" || mode == ">"){
4883 var utag = tagName.toUpperCase();
4884 for(var i = 0, ni, cn; ni = ns[i]; i++){
4885 cn = ni.children || ni.childNodes;
4886 for(var j = 0, cj; cj = cn[j]; j++){
4887 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4892 }else if(mode == "+"){
4893 var utag = tagName.toUpperCase();
4894 for(var i = 0, n; n = ns[i]; i++){
4895 while((n = n.nextSibling) && n.nodeType != 1);
4896 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4900 }else if(mode == "~"){
4901 for(var i = 0, n; n = ns[i]; i++){
4902 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4911 function concat(a, b){
4915 for(var i = 0, l = b.length; i < l; i++){
4921 function byTag(cs, tagName){
4922 if(cs.tagName || cs == document){
4928 var r = [], ri = -1;
4929 tagName = tagName.toLowerCase();
4930 for(var i = 0, ci; ci = cs[i]; i++){
4931 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4938 function byId(cs, attr, id){
4939 if(cs.tagName || cs == document){
4945 var r = [], ri = -1;
4946 for(var i = 0,ci; ci = cs[i]; i++){
4947 if(ci && ci.id == id){
4955 function byAttribute(cs, attr, value, op, custom){
4956 var r = [], ri = -1, st = custom=="{";
4957 var f = Roo.DomQuery.operators[op];
4958 for(var i = 0, ci; ci = cs[i]; i++){
4961 a = Roo.DomQuery.getStyle(ci, attr);
4963 else if(attr == "class" || attr == "className"){
4965 }else if(attr == "for"){
4967 }else if(attr == "href"){
4968 a = ci.getAttribute("href", 2);
4970 a = ci.getAttribute(attr);
4972 if((f && f(a, value)) || (!f && a)){
4979 function byPseudo(cs, name, value){
4980 return Roo.DomQuery.pseudos[name](cs, value);
4983 // This is for IE MSXML which does not support expandos.
4984 // IE runs the same speed using setAttribute, however FF slows way down
4985 // and Safari completely fails so they need to continue to use expandos.
4986 var isIE = window.ActiveXObject ? true : false;
4988 // this eval is stop the compressor from
4989 // renaming the variable to something shorter
4991 /** eval:var:batch */
4996 function nodupIEXml(cs){
4998 cs[0].setAttribute("_nodup", d);
5000 for(var i = 1, len = cs.length; i < len; i++){
5002 if(!c.getAttribute("_nodup") != d){
5003 c.setAttribute("_nodup", d);
5007 for(var i = 0, len = cs.length; i < len; i++){
5008 cs[i].removeAttribute("_nodup");
5017 var len = cs.length, c, i, r = cs, cj, ri = -1;
5018 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5021 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5022 return nodupIEXml(cs);
5026 for(i = 1; c = cs[i]; i++){
5031 for(var j = 0; j < i; j++){
5034 for(j = i+1; cj = cs[j]; j++){
5046 function quickDiffIEXml(c1, c2){
5048 for(var i = 0, len = c1.length; i < len; i++){
5049 c1[i].setAttribute("_qdiff", d);
5052 for(var i = 0, len = c2.length; i < len; i++){
5053 if(c2[i].getAttribute("_qdiff") != d){
5054 r[r.length] = c2[i];
5057 for(var i = 0, len = c1.length; i < len; i++){
5058 c1[i].removeAttribute("_qdiff");
5063 function quickDiff(c1, c2){
5064 var len1 = c1.length;
5068 if(isIE && c1[0].selectSingleNode){
5069 return quickDiffIEXml(c1, c2);
5072 for(var i = 0; i < len1; i++){
5076 for(var i = 0, len = c2.length; i < len; i++){
5077 if(c2[i]._qdiff != d){
5078 r[r.length] = c2[i];
5084 function quickId(ns, mode, root, id){
5086 var d = root.ownerDocument || root;
5087 return d.getElementById(id);
5089 ns = getNodes(ns, mode, "*");
5090 return byId(ns, null, id);
5094 getStyle : function(el, name){
5095 return Roo.fly(el).getStyle(name);
5098 * Compiles a selector/xpath query into a reusable function. The returned function
5099 * takes one parameter "root" (optional), which is the context node from where the query should start.
5100 * @param {String} selector The selector/xpath query
5101 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5102 * @return {Function}
5104 compile : function(path, type){
5105 type = type || "select";
5107 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5108 var q = path, mode, lq;
5109 var tk = Roo.DomQuery.matchers;
5110 var tklen = tk.length;
5113 // accept leading mode switch
5114 var lmode = q.match(modeRe);
5115 if(lmode && lmode[1]){
5116 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5117 q = q.replace(lmode[1], "");
5119 // strip leading slashes
5120 while(path.substr(0, 1)=="/"){
5121 path = path.substr(1);
5124 while(q && lq != q){
5126 var tm = q.match(tagTokenRe);
5127 if(type == "select"){
5130 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5132 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5134 q = q.replace(tm[0], "");
5135 }else if(q.substr(0, 1) != '@'){
5136 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5141 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5143 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5145 q = q.replace(tm[0], "");
5148 while(!(mm = q.match(modeRe))){
5149 var matched = false;
5150 for(var j = 0; j < tklen; j++){
5152 var m = q.match(t.re);
5154 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5157 q = q.replace(m[0], "");
5162 // prevent infinite loop on bad selector
5164 throw 'Error parsing selector, parsing failed at "' + q + '"';
5168 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5169 q = q.replace(mm[1], "");
5172 fn[fn.length] = "return nodup(n);\n}";
5175 * list of variables that need from compression as they are used by eval.
5185 * eval:var:byClassName
5187 * eval:var:byAttribute
5188 * eval:var:attrValue
5196 * Selects a group of elements.
5197 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5198 * @param {Node} root (optional) The start of the query (defaults to document).
5201 select : function(path, root, type){
5202 if(!root || root == document){
5205 if(typeof root == "string"){
5206 root = document.getElementById(root);
5208 var paths = path.split(",");
5210 for(var i = 0, len = paths.length; i < len; i++){
5211 var p = paths[i].replace(trimRe, "");
5213 cache[p] = Roo.DomQuery.compile(p);
5215 throw p + " is not a valid selector";
5218 var result = cache[p](root);
5219 if(result && result != document){
5220 results = results.concat(result);
5223 if(paths.length > 1){
5224 return nodup(results);
5230 * Selects a single element.
5231 * @param {String} selector The selector/xpath query
5232 * @param {Node} root (optional) The start of the query (defaults to document).
5235 selectNode : function(path, root){
5236 return Roo.DomQuery.select(path, root)[0];
5240 * Selects the value of a node, optionally replacing null with the defaultValue.
5241 * @param {String} selector The selector/xpath query
5242 * @param {Node} root (optional) The start of the query (defaults to document).
5243 * @param {String} defaultValue
5245 selectValue : function(path, root, defaultValue){
5246 path = path.replace(trimRe, "");
5247 if(!valueCache[path]){
5248 valueCache[path] = Roo.DomQuery.compile(path, "select");
5250 var n = valueCache[path](root);
5251 n = n[0] ? n[0] : n;
5252 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5253 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5257 * Selects the value of a node, parsing integers and floats.
5258 * @param {String} selector The selector/xpath query
5259 * @param {Node} root (optional) The start of the query (defaults to document).
5260 * @param {Number} defaultValue
5263 selectNumber : function(path, root, defaultValue){
5264 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5265 return parseFloat(v);
5269 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5270 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5271 * @param {String} selector The simple selector to test
5274 is : function(el, ss){
5275 if(typeof el == "string"){
5276 el = document.getElementById(el);
5278 var isArray = (el instanceof Array);
5279 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5280 return isArray ? (result.length == el.length) : (result.length > 0);
5284 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5285 * @param {Array} el An array of elements to filter
5286 * @param {String} selector The simple selector to test
5287 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5288 * the selector instead of the ones that match
5291 filter : function(els, ss, nonMatches){
5292 ss = ss.replace(trimRe, "");
5293 if(!simpleCache[ss]){
5294 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5296 var result = simpleCache[ss](els);
5297 return nonMatches ? quickDiff(result, els) : result;
5301 * Collection of matching regular expressions and code snippets.
5305 select: 'n = byClassName(n, null, " {1} ");'
5307 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5308 select: 'n = byPseudo(n, "{1}", "{2}");'
5310 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5311 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5314 select: 'n = byId(n, null, "{1}");'
5317 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5322 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5323 * 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, > <.
5326 "=" : function(a, v){
5329 "!=" : function(a, v){
5332 "^=" : function(a, v){
5333 return a && a.substr(0, v.length) == v;
5335 "$=" : function(a, v){
5336 return a && a.substr(a.length-v.length) == v;
5338 "*=" : function(a, v){
5339 return a && a.indexOf(v) !== -1;
5341 "%=" : function(a, v){
5342 return (a % v) == 0;
5344 "|=" : function(a, v){
5345 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5347 "~=" : function(a, v){
5348 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5353 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5354 * and the argument (if any) supplied in the selector.
5357 "first-child" : function(c){
5358 var r = [], ri = -1, n;
5359 for(var i = 0, ci; ci = n = c[i]; i++){
5360 while((n = n.previousSibling) && n.nodeType != 1);
5368 "last-child" : function(c){
5369 var r = [], ri = -1, n;
5370 for(var i = 0, ci; ci = n = c[i]; i++){
5371 while((n = n.nextSibling) && n.nodeType != 1);
5379 "nth-child" : function(c, a) {
5380 var r = [], ri = -1;
5381 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5382 var f = (m[1] || 1) - 0, l = m[2] - 0;
5383 for(var i = 0, n; n = c[i]; i++){
5384 var pn = n.parentNode;
5385 if (batch != pn._batch) {
5387 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5388 if(cn.nodeType == 1){
5395 if (l == 0 || n.nodeIndex == l){
5398 } else if ((n.nodeIndex + l) % f == 0){
5406 "only-child" : function(c){
5407 var r = [], ri = -1;;
5408 for(var i = 0, ci; ci = c[i]; i++){
5409 if(!prev(ci) && !next(ci)){
5416 "empty" : function(c){
5417 var r = [], ri = -1;
5418 for(var i = 0, ci; ci = c[i]; i++){
5419 var cns = ci.childNodes, j = 0, cn, empty = true;
5422 if(cn.nodeType == 1 || cn.nodeType == 3){
5434 "contains" : function(c, v){
5435 var r = [], ri = -1;
5436 for(var i = 0, ci; ci = c[i]; i++){
5437 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5444 "nodeValue" : function(c, v){
5445 var r = [], ri = -1;
5446 for(var i = 0, ci; ci = c[i]; i++){
5447 if(ci.firstChild && ci.firstChild.nodeValue == v){
5454 "checked" : function(c){
5455 var r = [], ri = -1;
5456 for(var i = 0, ci; ci = c[i]; i++){
5457 if(ci.checked == true){
5464 "not" : function(c, ss){
5465 return Roo.DomQuery.filter(c, ss, true);
5468 "odd" : function(c){
5469 return this["nth-child"](c, "odd");
5472 "even" : function(c){
5473 return this["nth-child"](c, "even");
5476 "nth" : function(c, a){
5477 return c[a-1] || [];
5480 "first" : function(c){
5484 "last" : function(c){
5485 return c[c.length-1] || [];
5488 "has" : function(c, ss){
5489 var s = Roo.DomQuery.select;
5490 var r = [], ri = -1;
5491 for(var i = 0, ci; ci = c[i]; i++){
5492 if(s(ss, ci).length > 0){
5499 "next" : function(c, ss){
5500 var is = Roo.DomQuery.is;
5501 var r = [], ri = -1;
5502 for(var i = 0, ci; ci = c[i]; i++){
5511 "prev" : function(c, ss){
5512 var is = Roo.DomQuery.is;
5513 var r = [], ri = -1;
5514 for(var i = 0, ci; ci = c[i]; i++){
5527 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5528 * @param {String} path The selector/xpath query
5529 * @param {Node} root (optional) The start of the query (defaults to document).
5534 Roo.query = Roo.DomQuery.select;
5537 * Ext JS Library 1.1.1
5538 * Copyright(c) 2006-2007, Ext JS, LLC.
5540 * Originally Released Under LGPL - original licence link has changed is not relivant.
5543 * <script type="text/javascript">
5547 * @class Roo.util.Observable
5548 * Base class that provides a common interface for publishing events. Subclasses are expected to
5549 * to have a property "events" with all the events defined.<br>
5552 Employee = function(name){
5559 Roo.extend(Employee, Roo.util.Observable);
5561 * @param {Object} config properties to use (incuding events / listeners)
5564 Roo.util.Observable = function(cfg){
5567 this.addEvents(cfg.events || {});
5569 delete cfg.events; // make sure
5572 Roo.apply(this, cfg);
5575 this.on(this.listeners);
5576 delete this.listeners;
5579 Roo.util.Observable.prototype = {
5581 * @cfg {Object} listeners list of events and functions to call for this object,
5585 'click' : function(e) {
5595 * Fires the specified event with the passed parameters (minus the event name).
5596 * @param {String} eventName
5597 * @param {Object...} args Variable number of parameters are passed to handlers
5598 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5600 fireEvent : function(){
5601 var ce = this.events[arguments[0].toLowerCase()];
5602 if(typeof ce == "object"){
5603 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5610 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5613 * Appends an event handler to this component
5614 * @param {String} eventName The type of event to listen for
5615 * @param {Function} handler The method the event invokes
5616 * @param {Object} scope (optional) The scope in which to execute the handler
5617 * function. The handler function's "this" context.
5618 * @param {Object} options (optional) An object containing handler configuration
5619 * properties. This may contain any of the following properties:<ul>
5620 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5621 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5622 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5623 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5624 * by the specified number of milliseconds. If the event fires again within that time, the original
5625 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5628 * <b>Combining Options</b><br>
5629 * Using the options argument, it is possible to combine different types of listeners:<br>
5631 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5633 el.on('click', this.onClick, this, {
5640 * <b>Attaching multiple handlers in 1 call</b><br>
5641 * The method also allows for a single argument to be passed which is a config object containing properties
5642 * which specify multiple handlers.
5651 fn: this.onMouseOver,
5655 fn: this.onMouseOut,
5661 * Or a shorthand syntax which passes the same scope object to all handlers:
5664 'click': this.onClick,
5665 'mouseover': this.onMouseOver,
5666 'mouseout': this.onMouseOut,
5671 addListener : function(eventName, fn, scope, o){
5672 if(typeof eventName == "object"){
5675 if(this.filterOptRe.test(e)){
5678 if(typeof o[e] == "function"){
5680 this.addListener(e, o[e], o.scope, o);
5682 // individual options
5683 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5688 o = (!o || typeof o == "boolean") ? {} : o;
5689 eventName = eventName.toLowerCase();
5690 var ce = this.events[eventName] || true;
5691 if(typeof ce == "boolean"){
5692 ce = new Roo.util.Event(this, eventName);
5693 this.events[eventName] = ce;
5695 ce.addListener(fn, scope, o);
5699 * Removes a listener
5700 * @param {String} eventName The type of event to listen for
5701 * @param {Function} handler The handler to remove
5702 * @param {Object} scope (optional) The scope (this object) for the handler
5704 removeListener : function(eventName, fn, scope){
5705 var ce = this.events[eventName.toLowerCase()];
5706 if(typeof ce == "object"){
5707 ce.removeListener(fn, scope);
5712 * Removes all listeners for this object
5714 purgeListeners : function(){
5715 for(var evt in this.events){
5716 if(typeof this.events[evt] == "object"){
5717 this.events[evt].clearListeners();
5722 relayEvents : function(o, events){
5723 var createHandler = function(ename){
5725 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5728 for(var i = 0, len = events.length; i < len; i++){
5729 var ename = events[i];
5730 if(!this.events[ename]){ this.events[ename] = true; };
5731 o.on(ename, createHandler(ename), this);
5736 * Used to define events on this Observable
5737 * @param {Object} object The object with the events defined
5739 addEvents : function(o){
5743 Roo.applyIf(this.events, o);
5747 * Checks to see if this object has any listeners for a specified event
5748 * @param {String} eventName The name of the event to check for
5749 * @return {Boolean} True if the event is being listened for, else false
5751 hasListener : function(eventName){
5752 var e = this.events[eventName];
5753 return typeof e == "object" && e.listeners.length > 0;
5757 * Appends an event handler to this element (shorthand for addListener)
5758 * @param {String} eventName The type of event to listen for
5759 * @param {Function} handler The method the event invokes
5760 * @param {Object} scope (optional) The scope in which to execute the handler
5761 * function. The handler function's "this" context.
5762 * @param {Object} options (optional)
5765 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5767 * Removes a listener (shorthand for removeListener)
5768 * @param {String} eventName The type of event to listen for
5769 * @param {Function} handler The handler to remove
5770 * @param {Object} scope (optional) The scope (this object) for the handler
5773 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5776 * Starts capture on the specified Observable. All events will be passed
5777 * to the supplied function with the event name + standard signature of the event
5778 * <b>before</b> the event is fired. If the supplied function returns false,
5779 * the event will not fire.
5780 * @param {Observable} o The Observable to capture
5781 * @param {Function} fn The function to call
5782 * @param {Object} scope (optional) The scope (this object) for the fn
5785 Roo.util.Observable.capture = function(o, fn, scope){
5786 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5790 * Removes <b>all</b> added captures from the Observable.
5791 * @param {Observable} o The Observable to release
5794 Roo.util.Observable.releaseCapture = function(o){
5795 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5800 var createBuffered = function(h, o, scope){
5801 var task = new Roo.util.DelayedTask();
5803 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5807 var createSingle = function(h, e, fn, scope){
5809 e.removeListener(fn, scope);
5810 return h.apply(scope, arguments);
5814 var createDelayed = function(h, o, scope){
5816 var args = Array.prototype.slice.call(arguments, 0);
5817 setTimeout(function(){
5818 h.apply(scope, args);
5823 Roo.util.Event = function(obj, name){
5826 this.listeners = [];
5829 Roo.util.Event.prototype = {
5830 addListener : function(fn, scope, options){
5831 var o = options || {};
5832 scope = scope || this.obj;
5833 if(!this.isListening(fn, scope)){
5834 var l = {fn: fn, scope: scope, options: o};
5837 h = createDelayed(h, o, scope);
5840 h = createSingle(h, this, fn, scope);
5843 h = createBuffered(h, o, scope);
5846 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5847 this.listeners.push(l);
5849 this.listeners = this.listeners.slice(0);
5850 this.listeners.push(l);
5855 findListener : function(fn, scope){
5856 scope = scope || this.obj;
5857 var ls = this.listeners;
5858 for(var i = 0, len = ls.length; i < len; i++){
5860 if(l.fn == fn && l.scope == scope){
5867 isListening : function(fn, scope){
5868 return this.findListener(fn, scope) != -1;
5871 removeListener : function(fn, scope){
5873 if((index = this.findListener(fn, scope)) != -1){
5875 this.listeners.splice(index, 1);
5877 this.listeners = this.listeners.slice(0);
5878 this.listeners.splice(index, 1);
5885 clearListeners : function(){
5886 this.listeners = [];
5890 var ls = this.listeners, scope, len = ls.length;
5893 var args = Array.prototype.slice.call(arguments, 0);
5894 for(var i = 0; i < len; i++){
5896 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5897 this.firing = false;
5901 this.firing = false;
5908 * Ext JS Library 1.1.1
5909 * Copyright(c) 2006-2007, Ext JS, LLC.
5911 * Originally Released Under LGPL - original licence link has changed is not relivant.
5914 * <script type="text/javascript">
5918 * @class Roo.EventManager
5919 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5920 * several useful events directly.
5921 * See {@link Roo.EventObject} for more details on normalized event objects.
5924 Roo.EventManager = function(){
5925 var docReadyEvent, docReadyProcId, docReadyState = false;
5926 var resizeEvent, resizeTask, textEvent, textSize;
5927 var E = Roo.lib.Event;
5928 var D = Roo.lib.Dom;
5931 var fireDocReady = function(){
5933 docReadyState = true;
5936 clearInterval(docReadyProcId);
5938 if(Roo.isGecko || Roo.isOpera) {
5939 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5942 var defer = document.getElementById("ie-deferred-loader");
5944 defer.onreadystatechange = null;
5945 defer.parentNode.removeChild(defer);
5949 docReadyEvent.fire();
5950 docReadyEvent.clearListeners();
5955 var initDocReady = function(){
5956 docReadyEvent = new Roo.util.Event();
5957 if(Roo.isGecko || Roo.isOpera) {
5958 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5960 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5961 var defer = document.getElementById("ie-deferred-loader");
5962 defer.onreadystatechange = function(){
5963 if(this.readyState == "complete"){
5967 }else if(Roo.isSafari){
5968 docReadyProcId = setInterval(function(){
5969 var rs = document.readyState;
5970 if(rs == "complete") {
5975 // no matter what, make sure it fires on load
5976 E.on(window, "load", fireDocReady);
5979 var createBuffered = function(h, o){
5980 var task = new Roo.util.DelayedTask(h);
5982 // create new event object impl so new events don't wipe out properties
5983 e = new Roo.EventObjectImpl(e);
5984 task.delay(o.buffer, h, null, [e]);
5988 var createSingle = function(h, el, ename, fn){
5990 Roo.EventManager.removeListener(el, ename, fn);
5995 var createDelayed = function(h, o){
5997 // create new event object impl so new events don't wipe out properties
5998 e = new Roo.EventObjectImpl(e);
5999 setTimeout(function(){
6005 var listen = function(element, ename, opt, fn, scope){
6006 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6007 fn = fn || o.fn; scope = scope || o.scope;
6008 var el = Roo.getDom(element);
6010 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6012 var h = function(e){
6013 e = Roo.EventObject.setEvent(e);
6016 t = e.getTarget(o.delegate, el);
6023 if(o.stopEvent === true){
6026 if(o.preventDefault === true){
6029 if(o.stopPropagation === true){
6030 e.stopPropagation();
6033 if(o.normalized === false){
6037 fn.call(scope || el, e, t, o);
6040 h = createDelayed(h, o);
6043 h = createSingle(h, el, ename, fn);
6046 h = createBuffered(h, o);
6048 fn._handlers = fn._handlers || [];
6049 fn._handlers.push([Roo.id(el), ename, h]);
6052 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6053 el.addEventListener("DOMMouseScroll", h, false);
6054 E.on(window, 'unload', function(){
6055 el.removeEventListener("DOMMouseScroll", h, false);
6058 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6059 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6064 var stopListening = function(el, ename, fn){
6065 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6067 for(var i = 0, len = hds.length; i < len; i++){
6069 if(h[0] == id && h[1] == ename){
6076 E.un(el, ename, hd);
6077 el = Roo.getDom(el);
6078 if(ename == "mousewheel" && el.addEventListener){
6079 el.removeEventListener("DOMMouseScroll", hd, false);
6081 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6082 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6086 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6093 * @scope Roo.EventManager
6098 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6099 * object with a Roo.EventObject
6100 * @param {Function} fn The method the event invokes
6101 * @param {Object} scope An object that becomes the scope of the handler
6102 * @param {boolean} override If true, the obj passed in becomes
6103 * the execution scope of the listener
6104 * @return {Function} The wrapped function
6107 wrap : function(fn, scope, override){
6109 Roo.EventObject.setEvent(e);
6110 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6115 * Appends an event handler to an element (shorthand for addListener)
6116 * @param {String/HTMLElement} element The html element or id to assign the
6117 * @param {String} eventName The type of event to listen for
6118 * @param {Function} handler The method the event invokes
6119 * @param {Object} scope (optional) The scope in which to execute the handler
6120 * function. The handler function's "this" context.
6121 * @param {Object} options (optional) An object containing handler configuration
6122 * properties. This may contain any of the following properties:<ul>
6123 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6124 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6125 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6126 * <li>preventDefault {Boolean} True to prevent the default action</li>
6127 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6128 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6129 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6130 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6131 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6132 * by the specified number of milliseconds. If the event fires again within that time, the original
6133 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6136 * <b>Combining Options</b><br>
6137 * Using the options argument, it is possible to combine different types of listeners:<br>
6139 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6141 el.on('click', this.onClick, this, {
6148 * <b>Attaching multiple handlers in 1 call</b><br>
6149 * The method also allows for a single argument to be passed which is a config object containing properties
6150 * which specify multiple handlers.
6160 fn: this.onMouseOver
6169 * Or a shorthand syntax:<br>
6172 'click' : this.onClick,
6173 'mouseover' : this.onMouseOver,
6174 'mouseout' : this.onMouseOut
6178 addListener : function(element, eventName, fn, scope, options){
6179 if(typeof eventName == "object"){
6185 if(typeof o[e] == "function"){
6187 listen(element, e, o, o[e], o.scope);
6189 // individual options
6190 listen(element, e, o[e]);
6195 return listen(element, eventName, options, fn, scope);
6199 * Removes an event handler
6201 * @param {String/HTMLElement} element The id or html element to remove the
6203 * @param {String} eventName The type of event
6204 * @param {Function} fn
6205 * @return {Boolean} True if a listener was actually removed
6207 removeListener : function(element, eventName, fn){
6208 return stopListening(element, eventName, fn);
6212 * Fires when the document is ready (before onload and before images are loaded). Can be
6213 * accessed shorthanded Roo.onReady().
6214 * @param {Function} fn The method the event invokes
6215 * @param {Object} scope An object that becomes the scope of the handler
6216 * @param {boolean} options
6218 onDocumentReady : function(fn, scope, options){
6219 if(docReadyState){ // if it already fired
6220 docReadyEvent.addListener(fn, scope, options);
6221 docReadyEvent.fire();
6222 docReadyEvent.clearListeners();
6228 docReadyEvent.addListener(fn, scope, options);
6232 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6233 * @param {Function} fn The method the event invokes
6234 * @param {Object} scope An object that becomes the scope of the handler
6235 * @param {boolean} options
6237 onWindowResize : function(fn, scope, options){
6239 resizeEvent = new Roo.util.Event();
6240 resizeTask = new Roo.util.DelayedTask(function(){
6241 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6243 E.on(window, "resize", function(){
6245 resizeTask.delay(50);
6247 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6251 resizeEvent.addListener(fn, scope, options);
6255 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6256 * @param {Function} fn The method the event invokes
6257 * @param {Object} scope An object that becomes the scope of the handler
6258 * @param {boolean} options
6260 onTextResize : function(fn, scope, options){
6262 textEvent = new Roo.util.Event();
6263 var textEl = new Roo.Element(document.createElement('div'));
6264 textEl.dom.className = 'x-text-resize';
6265 textEl.dom.innerHTML = 'X';
6266 textEl.appendTo(document.body);
6267 textSize = textEl.dom.offsetHeight;
6268 setInterval(function(){
6269 if(textEl.dom.offsetHeight != textSize){
6270 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6272 }, this.textResizeInterval);
6274 textEvent.addListener(fn, scope, options);
6278 * Removes the passed window resize listener.
6279 * @param {Function} fn The method the event invokes
6280 * @param {Object} scope The scope of handler
6282 removeResizeListener : function(fn, scope){
6284 resizeEvent.removeListener(fn, scope);
6289 fireResize : function(){
6291 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6295 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6299 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6301 textResizeInterval : 50
6306 * @scopeAlias pub=Roo.EventManager
6310 * Appends an event handler to an element (shorthand for addListener)
6311 * @param {String/HTMLElement} element The html element or id to assign the
6312 * @param {String} eventName The type of event to listen for
6313 * @param {Function} handler The method the event invokes
6314 * @param {Object} scope (optional) The scope in which to execute the handler
6315 * function. The handler function's "this" context.
6316 * @param {Object} options (optional) An object containing handler configuration
6317 * properties. This may contain any of the following properties:<ul>
6318 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6319 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6320 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6321 * <li>preventDefault {Boolean} True to prevent the default action</li>
6322 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6323 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6324 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6325 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6326 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6327 * by the specified number of milliseconds. If the event fires again within that time, the original
6328 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6331 * <b>Combining Options</b><br>
6332 * Using the options argument, it is possible to combine different types of listeners:<br>
6334 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6336 el.on('click', this.onClick, this, {
6343 * <b>Attaching multiple handlers in 1 call</b><br>
6344 * The method also allows for a single argument to be passed which is a config object containing properties
6345 * which specify multiple handlers.
6355 fn: this.onMouseOver
6364 * Or a shorthand syntax:<br>
6367 'click' : this.onClick,
6368 'mouseover' : this.onMouseOver,
6369 'mouseout' : this.onMouseOut
6373 pub.on = pub.addListener;
6374 pub.un = pub.removeListener;
6376 pub.stoppedMouseDownEvent = new Roo.util.Event();
6380 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6381 * @param {Function} fn The method the event invokes
6382 * @param {Object} scope An object that becomes the scope of the handler
6383 * @param {boolean} override If true, the obj passed in becomes
6384 * the execution scope of the listener
6388 Roo.onReady = Roo.EventManager.onDocumentReady;
6390 Roo.onReady(function(){
6391 var bd = Roo.get(document.body);
6396 : Roo.isGecko ? "roo-gecko"
6397 : Roo.isOpera ? "roo-opera"
6398 : Roo.isSafari ? "roo-safari" : ""];
6401 cls.push("roo-mac");
6404 cls.push("roo-linux");
6406 if(Roo.isBorderBox){
6407 cls.push('roo-border-box');
6409 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6410 var p = bd.dom.parentNode;
6412 p.className += ' roo-strict';
6415 bd.addClass(cls.join(' '));
6419 * @class Roo.EventObject
6420 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6421 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6424 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6426 var target = e.getTarget();
6429 var myDiv = Roo.get("myDiv");
6430 myDiv.on("click", handleClick);
6432 Roo.EventManager.on("myDiv", 'click', handleClick);
6433 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6437 Roo.EventObject = function(){
6439 var E = Roo.lib.Event;
6441 // safari keypress events for special keys return bad keycodes
6444 63235 : 39, // right
6447 63276 : 33, // page up
6448 63277 : 34, // page down
6449 63272 : 46, // delete
6454 // normalize button clicks
6455 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6456 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6458 Roo.EventObjectImpl = function(e){
6460 this.setEvent(e.browserEvent || e);
6463 Roo.EventObjectImpl.prototype = {
6465 * Used to fix doc tools.
6466 * @scope Roo.EventObject.prototype
6472 /** The normal browser event */
6473 browserEvent : null,
6474 /** The button pressed in a mouse event */
6476 /** True if the shift key was down during the event */
6478 /** True if the control key was down during the event */
6480 /** True if the alt key was down during the event */
6539 setEvent : function(e){
6540 if(e == this || (e && e.browserEvent)){ // already wrapped
6543 this.browserEvent = e;
6545 // normalize buttons
6546 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6547 if(e.type == 'click' && this.button == -1){
6551 this.shiftKey = e.shiftKey;
6552 // mac metaKey behaves like ctrlKey
6553 this.ctrlKey = e.ctrlKey || e.metaKey;
6554 this.altKey = e.altKey;
6555 // in getKey these will be normalized for the mac
6556 this.keyCode = e.keyCode;
6557 // keyup warnings on firefox.
6558 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6559 // cache the target for the delayed and or buffered events
6560 this.target = E.getTarget(e);
6562 this.xy = E.getXY(e);
6565 this.shiftKey = false;
6566 this.ctrlKey = false;
6567 this.altKey = false;
6577 * Stop the event (preventDefault and stopPropagation)
6579 stopEvent : function(){
6580 if(this.browserEvent){
6581 if(this.browserEvent.type == 'mousedown'){
6582 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6584 E.stopEvent(this.browserEvent);
6589 * Prevents the browsers default handling of the event.
6591 preventDefault : function(){
6592 if(this.browserEvent){
6593 E.preventDefault(this.browserEvent);
6598 isNavKeyPress : function(){
6599 var k = this.keyCode;
6600 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6601 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6604 isSpecialKey : function(){
6605 var k = this.keyCode;
6606 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6607 (k == 16) || (k == 17) ||
6608 (k >= 18 && k <= 20) ||
6609 (k >= 33 && k <= 35) ||
6610 (k >= 36 && k <= 39) ||
6611 (k >= 44 && k <= 45);
6614 * Cancels bubbling of the event.
6616 stopPropagation : function(){
6617 if(this.browserEvent){
6618 if(this.type == 'mousedown'){
6619 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6621 E.stopPropagation(this.browserEvent);
6626 * Gets the key code for the event.
6629 getCharCode : function(){
6630 return this.charCode || this.keyCode;
6634 * Returns a normalized keyCode for the event.
6635 * @return {Number} The key code
6637 getKey : function(){
6638 var k = this.keyCode || this.charCode;
6639 return Roo.isSafari ? (safariKeys[k] || k) : k;
6643 * Gets the x coordinate of the event.
6646 getPageX : function(){
6651 * Gets the y coordinate of the event.
6654 getPageY : function(){
6659 * Gets the time of the event.
6662 getTime : function(){
6663 if(this.browserEvent){
6664 return E.getTime(this.browserEvent);
6670 * Gets the page coordinates of the event.
6671 * @return {Array} The xy values like [x, y]
6678 * Gets the target for the event.
6679 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6680 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6681 search as a number or element (defaults to 10 || document.body)
6682 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6683 * @return {HTMLelement}
6685 getTarget : function(selector, maxDepth, returnEl){
6686 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6689 * Gets the related target.
6690 * @return {HTMLElement}
6692 getRelatedTarget : function(){
6693 if(this.browserEvent){
6694 return E.getRelatedTarget(this.browserEvent);
6700 * Normalizes mouse wheel delta across browsers
6701 * @return {Number} The delta
6703 getWheelDelta : function(){
6704 var e = this.browserEvent;
6706 if(e.wheelDelta){ /* IE/Opera. */
6707 delta = e.wheelDelta/120;
6708 }else if(e.detail){ /* Mozilla case. */
6709 delta = -e.detail/3;
6715 * Returns true if the control, meta, shift or alt key was pressed during this event.
6718 hasModifier : function(){
6719 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6723 * Returns true if the target of this event equals el or is a child of el
6724 * @param {String/HTMLElement/Element} el
6725 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6728 within : function(el, related){
6729 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6730 return t && Roo.fly(el).contains(t);
6733 getPoint : function(){
6734 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6738 return new Roo.EventObjectImpl();
6743 * Ext JS Library 1.1.1
6744 * Copyright(c) 2006-2007, Ext JS, LLC.
6746 * Originally Released Under LGPL - original licence link has changed is not relivant.
6749 * <script type="text/javascript">
6753 // was in Composite Element!??!?!
6756 var D = Roo.lib.Dom;
6757 var E = Roo.lib.Event;
6758 var A = Roo.lib.Anim;
6760 // local style camelizing for speed
6762 var camelRe = /(-[a-z])/gi;
6763 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6764 var view = document.defaultView;
6767 * @class Roo.Element
6768 * Represents an Element in the DOM.<br><br>
6771 var el = Roo.get("my-div");
6774 var el = getEl("my-div");
6776 // or with a DOM element
6777 var el = Roo.get(myDivElement);
6779 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6780 * each call instead of constructing a new one.<br><br>
6781 * <b>Animations</b><br />
6782 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6783 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6785 Option Default Description
6786 --------- -------- ---------------------------------------------
6787 duration .35 The duration of the animation in seconds
6788 easing easeOut The YUI easing method
6789 callback none A function to execute when the anim completes
6790 scope this The scope (this) of the callback function
6792 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6793 * manipulate the animation. Here's an example:
6795 var el = Roo.get("my-div");
6800 // default animation
6801 el.setWidth(100, true);
6803 // animation with some options set
6810 // using the "anim" property to get the Anim object
6816 el.setWidth(100, opt);
6818 if(opt.anim.isAnimated()){
6822 * <b> Composite (Collections of) Elements</b><br />
6823 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6824 * @constructor Create a new Element directly.
6825 * @param {String/HTMLElement} element
6826 * @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).
6828 Roo.Element = function(element, forceNew){
6829 var dom = typeof element == "string" ?
6830 document.getElementById(element) : element;
6831 if(!dom){ // invalid id/element
6835 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6836 return Roo.Element.cache[id];
6846 * The DOM element ID
6849 this.id = id || Roo.id(dom);
6852 var El = Roo.Element;
6856 * The element's default display mode (defaults to "")
6859 originalDisplay : "",
6863 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6868 * Sets the element's visibility mode. When setVisible() is called it
6869 * will use this to determine whether to set the visibility or the display property.
6870 * @param visMode Element.VISIBILITY or Element.DISPLAY
6871 * @return {Roo.Element} this
6873 setVisibilityMode : function(visMode){
6874 this.visibilityMode = visMode;
6878 * Convenience method for setVisibilityMode(Element.DISPLAY)
6879 * @param {String} display (optional) What to set display to when visible
6880 * @return {Roo.Element} this
6882 enableDisplayMode : function(display){
6883 this.setVisibilityMode(El.DISPLAY);
6884 if(typeof display != "undefined") this.originalDisplay = display;
6889 * 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)
6890 * @param {String} selector The simple selector to test
6891 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6892 search as a number or element (defaults to 10 || document.body)
6893 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6894 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6896 findParent : function(simpleSelector, maxDepth, returnEl){
6897 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6898 maxDepth = maxDepth || 50;
6899 if(typeof maxDepth != "number"){
6900 stopEl = Roo.getDom(maxDepth);
6903 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6904 if(dq.is(p, simpleSelector)){
6905 return returnEl ? Roo.get(p) : p;
6915 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6916 * @param {String} selector The simple selector to test
6917 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6918 search as a number or element (defaults to 10 || document.body)
6919 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6920 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6922 findParentNode : function(simpleSelector, maxDepth, returnEl){
6923 var p = Roo.fly(this.dom.parentNode, '_internal');
6924 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6928 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6929 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6930 * @param {String} selector The simple selector to test
6931 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6932 search as a number or element (defaults to 10 || document.body)
6933 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6935 up : function(simpleSelector, maxDepth){
6936 return this.findParentNode(simpleSelector, maxDepth, true);
6942 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6943 * @param {String} selector The simple selector to test
6944 * @return {Boolean} True if this element matches the selector, else false
6946 is : function(simpleSelector){
6947 return Roo.DomQuery.is(this.dom, simpleSelector);
6951 * Perform animation on this element.
6952 * @param {Object} args The YUI animation control args
6953 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6954 * @param {Function} onComplete (optional) Function to call when animation completes
6955 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6956 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6957 * @return {Roo.Element} this
6959 animate : function(args, duration, onComplete, easing, animType){
6960 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6965 * @private Internal animation call
6967 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6968 animType = animType || 'run';
6970 var anim = Roo.lib.Anim[animType](
6972 (opt.duration || defaultDur) || .35,
6973 (opt.easing || defaultEase) || 'easeOut',
6975 Roo.callback(cb, this);
6976 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6984 // private legacy anim prep
6985 preanim : function(a, i){
6986 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6990 * Removes worthless text nodes
6991 * @param {Boolean} forceReclean (optional) By default the element
6992 * keeps track if it has been cleaned already so
6993 * you can call this over and over. However, if you update the element and
6994 * need to force a reclean, you can pass true.
6996 clean : function(forceReclean){
6997 if(this.isCleaned && forceReclean !== true){
7001 var d = this.dom, n = d.firstChild, ni = -1;
7003 var nx = n.nextSibling;
7004 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7011 this.isCleaned = true;
7016 calcOffsetsTo : function(el){
7019 var restorePos = false;
7020 if(el.getStyle('position') == 'static'){
7021 el.position('relative');
7026 while(op && op != d && op.tagName != 'HTML'){
7029 op = op.offsetParent;
7032 el.position('static');
7038 * Scrolls this element into view within the passed container.
7039 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7040 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7041 * @return {Roo.Element} this
7043 scrollIntoView : function(container, hscroll){
7044 var c = Roo.getDom(container) || document.body;
7047 var o = this.calcOffsetsTo(c),
7050 b = t+el.offsetHeight,
7051 r = l+el.offsetWidth;
7053 var ch = c.clientHeight;
7054 var ct = parseInt(c.scrollTop, 10);
7055 var cl = parseInt(c.scrollLeft, 10);
7057 var cr = cl + c.clientWidth;
7065 if(hscroll !== false){
7069 c.scrollLeft = r-c.clientWidth;
7076 scrollChildIntoView : function(child, hscroll){
7077 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7081 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7082 * the new height may not be available immediately.
7083 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7084 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7085 * @param {Function} onComplete (optional) Function to call when animation completes
7086 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7087 * @return {Roo.Element} this
7089 autoHeight : function(animate, duration, onComplete, easing){
7090 var oldHeight = this.getHeight();
7092 this.setHeight(1); // force clipping
7093 setTimeout(function(){
7094 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7096 this.setHeight(height);
7098 if(typeof onComplete == "function"){
7102 this.setHeight(oldHeight); // restore original height
7103 this.setHeight(height, animate, duration, function(){
7105 if(typeof onComplete == "function") onComplete();
7106 }.createDelegate(this), easing);
7108 }.createDelegate(this), 0);
7113 * Returns true if this element is an ancestor of the passed element
7114 * @param {HTMLElement/String} el The element to check
7115 * @return {Boolean} True if this element is an ancestor of el, else false
7117 contains : function(el){
7118 if(!el){return false;}
7119 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7123 * Checks whether the element is currently visible using both visibility and display properties.
7124 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7125 * @return {Boolean} True if the element is currently visible, else false
7127 isVisible : function(deep) {
7128 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7129 if(deep !== true || !vis){
7132 var p = this.dom.parentNode;
7133 while(p && p.tagName.toLowerCase() != "body"){
7134 if(!Roo.fly(p, '_isVisible').isVisible()){
7143 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7144 * @param {String} selector The CSS selector
7145 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7146 * @return {CompositeElement/CompositeElementLite} The composite element
7148 select : function(selector, unique){
7149 return El.select(selector, unique, this.dom);
7153 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7154 * @param {String} selector The CSS selector
7155 * @return {Array} An array of the matched nodes
7157 query : function(selector, unique){
7158 return Roo.DomQuery.select(selector, this.dom);
7162 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7163 * @param {String} selector The CSS selector
7164 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7165 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7167 child : function(selector, returnDom){
7168 var n = Roo.DomQuery.selectNode(selector, this.dom);
7169 return returnDom ? n : Roo.get(n);
7173 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7174 * @param {String} selector The CSS selector
7175 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7176 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7178 down : function(selector, returnDom){
7179 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7180 return returnDom ? n : Roo.get(n);
7184 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7185 * @param {String} group The group the DD object is member of
7186 * @param {Object} config The DD config object
7187 * @param {Object} overrides An object containing methods to override/implement on the DD object
7188 * @return {Roo.dd.DD} The DD object
7190 initDD : function(group, config, overrides){
7191 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7192 return Roo.apply(dd, overrides);
7196 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7197 * @param {String} group The group the DDProxy object is member of
7198 * @param {Object} config The DDProxy config object
7199 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7200 * @return {Roo.dd.DDProxy} The DDProxy object
7202 initDDProxy : function(group, config, overrides){
7203 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7204 return Roo.apply(dd, overrides);
7208 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7209 * @param {String} group The group the DDTarget object is member of
7210 * @param {Object} config The DDTarget config object
7211 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7212 * @return {Roo.dd.DDTarget} The DDTarget object
7214 initDDTarget : function(group, config, overrides){
7215 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7216 return Roo.apply(dd, overrides);
7220 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7221 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7222 * @param {Boolean} visible Whether the element is visible
7223 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7224 * @return {Roo.Element} this
7226 setVisible : function(visible, animate){
7228 if(this.visibilityMode == El.DISPLAY){
7229 this.setDisplayed(visible);
7232 this.dom.style.visibility = visible ? "visible" : "hidden";
7235 // closure for composites
7237 var visMode = this.visibilityMode;
7239 this.setOpacity(.01);
7240 this.setVisible(true);
7242 this.anim({opacity: { to: (visible?1:0) }},
7243 this.preanim(arguments, 1),
7244 null, .35, 'easeIn', function(){
7246 if(visMode == El.DISPLAY){
7247 dom.style.display = "none";
7249 dom.style.visibility = "hidden";
7251 Roo.get(dom).setOpacity(1);
7259 * Returns true if display is not "none"
7262 isDisplayed : function() {
7263 return this.getStyle("display") != "none";
7267 * Toggles the element's visibility or display, depending on visibility mode.
7268 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7269 * @return {Roo.Element} this
7271 toggle : function(animate){
7272 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7277 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7278 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7279 * @return {Roo.Element} this
7281 setDisplayed : function(value) {
7282 if(typeof value == "boolean"){
7283 value = value ? this.originalDisplay : "none";
7285 this.setStyle("display", value);
7290 * Tries to focus the element. Any exceptions are caught and ignored.
7291 * @return {Roo.Element} this
7293 focus : function() {
7301 * Tries to blur the element. Any exceptions are caught and ignored.
7302 * @return {Roo.Element} this
7312 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7313 * @param {String/Array} className The CSS class to add, or an array of classes
7314 * @return {Roo.Element} this
7316 addClass : function(className){
7317 if(className instanceof Array){
7318 for(var i = 0, len = className.length; i < len; i++) {
7319 this.addClass(className[i]);
7322 if(className && !this.hasClass(className)){
7323 this.dom.className = this.dom.className + " " + className;
7330 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7331 * @param {String/Array} className The CSS class to add, or an array of classes
7332 * @return {Roo.Element} this
7334 radioClass : function(className){
7335 var siblings = this.dom.parentNode.childNodes;
7336 for(var i = 0; i < siblings.length; i++) {
7337 var s = siblings[i];
7338 if(s.nodeType == 1){
7339 Roo.get(s).removeClass(className);
7342 this.addClass(className);
7347 * Removes one or more CSS classes from the element.
7348 * @param {String/Array} className The CSS class to remove, or an array of classes
7349 * @return {Roo.Element} this
7351 removeClass : function(className){
7352 if(!className || !this.dom.className){
7355 if(className instanceof Array){
7356 for(var i = 0, len = className.length; i < len; i++) {
7357 this.removeClass(className[i]);
7360 if(this.hasClass(className)){
7361 var re = this.classReCache[className];
7363 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7364 this.classReCache[className] = re;
7366 this.dom.className =
7367 this.dom.className.replace(re, " ");
7377 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7378 * @param {String} className The CSS class to toggle
7379 * @return {Roo.Element} this
7381 toggleClass : function(className){
7382 if(this.hasClass(className)){
7383 this.removeClass(className);
7385 this.addClass(className);
7391 * Checks if the specified CSS class exists on this element's DOM node.
7392 * @param {String} className The CSS class to check for
7393 * @return {Boolean} True if the class exists, else false
7395 hasClass : function(className){
7396 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7400 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7401 * @param {String} oldClassName The CSS class to replace
7402 * @param {String} newClassName The replacement CSS class
7403 * @return {Roo.Element} this
7405 replaceClass : function(oldClassName, newClassName){
7406 this.removeClass(oldClassName);
7407 this.addClass(newClassName);
7412 * Returns an object with properties matching the styles requested.
7413 * For example, el.getStyles('color', 'font-size', 'width') might return
7414 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7415 * @param {String} style1 A style name
7416 * @param {String} style2 A style name
7417 * @param {String} etc.
7418 * @return {Object} The style object
7420 getStyles : function(){
7421 var a = arguments, len = a.length, r = {};
7422 for(var i = 0; i < len; i++){
7423 r[a[i]] = this.getStyle(a[i]);
7429 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7430 * @param {String} property The style property whose value is returned.
7431 * @return {String} The current value of the style property for this element.
7433 getStyle : function(){
7434 return view && view.getComputedStyle ?
7436 var el = this.dom, v, cs, camel;
7437 if(prop == 'float'){
7440 if(el.style && (v = el.style[prop])){
7443 if(cs = view.getComputedStyle(el, "")){
7444 if(!(camel = propCache[prop])){
7445 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7452 var el = this.dom, v, cs, camel;
7453 if(prop == 'opacity'){
7454 if(typeof el.style.filter == 'string'){
7455 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7457 var fv = parseFloat(m[1]);
7459 return fv ? fv / 100 : 0;
7464 }else if(prop == 'float'){
7465 prop = "styleFloat";
7467 if(!(camel = propCache[prop])){
7468 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7470 if(v = el.style[camel]){
7473 if(cs = el.currentStyle){
7481 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7482 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7483 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7484 * @return {Roo.Element} this
7486 setStyle : function(prop, value){
7487 if(typeof prop == "string"){
7489 if (prop == 'float') {
7490 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7495 if(!(camel = propCache[prop])){
7496 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7499 if(camel == 'opacity') {
7500 this.setOpacity(value);
7502 this.dom.style[camel] = value;
7505 for(var style in prop){
7506 if(typeof prop[style] != "function"){
7507 this.setStyle(style, prop[style]);
7515 * More flexible version of {@link #setStyle} for setting style properties.
7516 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7517 * a function which returns such a specification.
7518 * @return {Roo.Element} this
7520 applyStyles : function(style){
7521 Roo.DomHelper.applyStyles(this.dom, style);
7526 * 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).
7527 * @return {Number} The X position of the element
7530 return D.getX(this.dom);
7534 * 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).
7535 * @return {Number} The Y position of the element
7538 return D.getY(this.dom);
7542 * 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).
7543 * @return {Array} The XY position of the element
7546 return D.getXY(this.dom);
7550 * 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).
7551 * @param {Number} The X position of the element
7552 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7553 * @return {Roo.Element} this
7555 setX : function(x, animate){
7557 D.setX(this.dom, x);
7559 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7565 * 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).
7566 * @param {Number} The Y position of the element
7567 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7568 * @return {Roo.Element} this
7570 setY : function(y, animate){
7572 D.setY(this.dom, y);
7574 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7580 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7581 * @param {String} left The left CSS property value
7582 * @return {Roo.Element} this
7584 setLeft : function(left){
7585 this.setStyle("left", this.addUnits(left));
7590 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7591 * @param {String} top The top CSS property value
7592 * @return {Roo.Element} this
7594 setTop : function(top){
7595 this.setStyle("top", this.addUnits(top));
7600 * Sets the element's CSS right style.
7601 * @param {String} right The right CSS property value
7602 * @return {Roo.Element} this
7604 setRight : function(right){
7605 this.setStyle("right", this.addUnits(right));
7610 * Sets the element's CSS bottom style.
7611 * @param {String} bottom The bottom CSS property value
7612 * @return {Roo.Element} this
7614 setBottom : function(bottom){
7615 this.setStyle("bottom", this.addUnits(bottom));
7620 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7621 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7622 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7623 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7624 * @return {Roo.Element} this
7626 setXY : function(pos, animate){
7628 D.setXY(this.dom, pos);
7630 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7636 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7637 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7638 * @param {Number} x X value for new position (coordinates are page-based)
7639 * @param {Number} y Y value for new position (coordinates are page-based)
7640 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7641 * @return {Roo.Element} this
7643 setLocation : function(x, y, animate){
7644 this.setXY([x, y], this.preanim(arguments, 2));
7649 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7650 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7651 * @param {Number} x X value for new position (coordinates are page-based)
7652 * @param {Number} y Y value for new position (coordinates are page-based)
7653 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7654 * @return {Roo.Element} this
7656 moveTo : function(x, y, animate){
7657 this.setXY([x, y], this.preanim(arguments, 2));
7662 * Returns the region of the given element.
7663 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7664 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7666 getRegion : function(){
7667 return D.getRegion(this.dom);
7671 * Returns the offset height of the element
7672 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7673 * @return {Number} The element's height
7675 getHeight : function(contentHeight){
7676 var h = this.dom.offsetHeight || 0;
7677 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7681 * Returns the offset width of the element
7682 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7683 * @return {Number} The element's width
7685 getWidth : function(contentWidth){
7686 var w = this.dom.offsetWidth || 0;
7687 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7691 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7692 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7693 * if a height has not been set using CSS.
7696 getComputedHeight : function(){
7697 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7699 h = parseInt(this.getStyle('height'), 10) || 0;
7700 if(!this.isBorderBox()){
7701 h += this.getFrameWidth('tb');
7708 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7709 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7710 * if a width has not been set using CSS.
7713 getComputedWidth : function(){
7714 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7716 w = parseInt(this.getStyle('width'), 10) || 0;
7717 if(!this.isBorderBox()){
7718 w += this.getFrameWidth('lr');
7725 * Returns the size of the element.
7726 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7727 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7729 getSize : function(contentSize){
7730 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7734 * Returns the width and height of the viewport.
7735 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7737 getViewSize : function(){
7738 var d = this.dom, doc = document, aw = 0, ah = 0;
7739 if(d == doc || d == doc.body){
7740 return {width : D.getViewWidth(), height: D.getViewHeight()};
7743 width : d.clientWidth,
7744 height: d.clientHeight
7750 * Returns the value of the "value" attribute
7751 * @param {Boolean} asNumber true to parse the value as a number
7752 * @return {String/Number}
7754 getValue : function(asNumber){
7755 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7759 adjustWidth : function(width){
7760 if(typeof width == "number"){
7761 if(this.autoBoxAdjust && !this.isBorderBox()){
7762 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7772 adjustHeight : function(height){
7773 if(typeof height == "number"){
7774 if(this.autoBoxAdjust && !this.isBorderBox()){
7775 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7785 * Set the width of the element
7786 * @param {Number} width The new width
7787 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7788 * @return {Roo.Element} this
7790 setWidth : function(width, animate){
7791 width = this.adjustWidth(width);
7793 this.dom.style.width = this.addUnits(width);
7795 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7801 * Set the height of the element
7802 * @param {Number} height The new height
7803 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7804 * @return {Roo.Element} this
7806 setHeight : function(height, animate){
7807 height = this.adjustHeight(height);
7809 this.dom.style.height = this.addUnits(height);
7811 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7817 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7818 * @param {Number} width The new width
7819 * @param {Number} height The new height
7820 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7821 * @return {Roo.Element} this
7823 setSize : function(width, height, animate){
7824 if(typeof width == "object"){ // in case of object from getSize()
7825 height = width.height; width = width.width;
7827 width = this.adjustWidth(width); height = this.adjustHeight(height);
7829 this.dom.style.width = this.addUnits(width);
7830 this.dom.style.height = this.addUnits(height);
7832 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7838 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7839 * @param {Number} x X value for new position (coordinates are page-based)
7840 * @param {Number} y Y value for new position (coordinates are page-based)
7841 * @param {Number} width The new width
7842 * @param {Number} height The new height
7843 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7844 * @return {Roo.Element} this
7846 setBounds : function(x, y, width, height, animate){
7848 this.setSize(width, height);
7849 this.setLocation(x, y);
7851 width = this.adjustWidth(width); height = this.adjustHeight(height);
7852 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7853 this.preanim(arguments, 4), 'motion');
7859 * 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.
7860 * @param {Roo.lib.Region} region The region to fill
7861 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7862 * @return {Roo.Element} this
7864 setRegion : function(region, animate){
7865 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7870 * Appends an event handler
7872 * @param {String} eventName The type of event to append
7873 * @param {Function} fn The method the event invokes
7874 * @param {Object} scope (optional) The scope (this object) of the fn
7875 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7877 addListener : function(eventName, fn, scope, options){
7879 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7884 * Removes an event handler from this element
7885 * @param {String} eventName the type of event to remove
7886 * @param {Function} fn the method the event invokes
7887 * @return {Roo.Element} this
7889 removeListener : function(eventName, fn){
7890 Roo.EventManager.removeListener(this.dom, eventName, fn);
7895 * Removes all previous added listeners from this element
7896 * @return {Roo.Element} this
7898 removeAllListeners : function(){
7899 E.purgeElement(this.dom);
7903 relayEvent : function(eventName, observable){
7904 this.on(eventName, function(e){
7905 observable.fireEvent(eventName, e);
7910 * Set the opacity of the element
7911 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7912 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7913 * @return {Roo.Element} this
7915 setOpacity : function(opacity, animate){
7917 var s = this.dom.style;
7920 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7921 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7923 s.opacity = opacity;
7926 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7932 * Gets the left X coordinate
7933 * @param {Boolean} local True to get the local css position instead of page coordinate
7936 getLeft : function(local){
7940 return parseInt(this.getStyle("left"), 10) || 0;
7945 * Gets the right X coordinate of the element (element X position + element width)
7946 * @param {Boolean} local True to get the local css position instead of page coordinate
7949 getRight : function(local){
7951 return this.getX() + this.getWidth();
7953 return (this.getLeft(true) + this.getWidth()) || 0;
7958 * Gets the top Y coordinate
7959 * @param {Boolean} local True to get the local css position instead of page coordinate
7962 getTop : function(local) {
7966 return parseInt(this.getStyle("top"), 10) || 0;
7971 * Gets the bottom Y coordinate of the element (element Y position + element height)
7972 * @param {Boolean} local True to get the local css position instead of page coordinate
7975 getBottom : function(local){
7977 return this.getY() + this.getHeight();
7979 return (this.getTop(true) + this.getHeight()) || 0;
7984 * Initializes positioning on this element. If a desired position is not passed, it will make the
7985 * the element positioned relative IF it is not already positioned.
7986 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7987 * @param {Number} zIndex (optional) The zIndex to apply
7988 * @param {Number} x (optional) Set the page X position
7989 * @param {Number} y (optional) Set the page Y position
7991 position : function(pos, zIndex, x, y){
7993 if(this.getStyle('position') == 'static'){
7994 this.setStyle('position', 'relative');
7997 this.setStyle("position", pos);
8000 this.setStyle("z-index", zIndex);
8002 if(x !== undefined && y !== undefined){
8004 }else if(x !== undefined){
8006 }else if(y !== undefined){
8012 * Clear positioning back to the default when the document was loaded
8013 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8014 * @return {Roo.Element} this
8016 clearPositioning : function(value){
8024 "position" : "static"
8030 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8031 * snapshot before performing an update and then restoring the element.
8034 getPositioning : function(){
8035 var l = this.getStyle("left");
8036 var t = this.getStyle("top");
8038 "position" : this.getStyle("position"),
8040 "right" : l ? "" : this.getStyle("right"),
8042 "bottom" : t ? "" : this.getStyle("bottom"),
8043 "z-index" : this.getStyle("z-index")
8048 * Gets the width of the border(s) for the specified side(s)
8049 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8050 * passing lr would get the border (l)eft width + the border (r)ight width.
8051 * @return {Number} The width of the sides passed added together
8053 getBorderWidth : function(side){
8054 return this.addStyles(side, El.borders);
8058 * Gets the width of the padding(s) for the specified side(s)
8059 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8060 * passing lr would get the padding (l)eft + the padding (r)ight.
8061 * @return {Number} The padding of the sides passed added together
8063 getPadding : function(side){
8064 return this.addStyles(side, El.paddings);
8068 * Set positioning with an object returned by getPositioning().
8069 * @param {Object} posCfg
8070 * @return {Roo.Element} this
8072 setPositioning : function(pc){
8073 this.applyStyles(pc);
8074 if(pc.right == "auto"){
8075 this.dom.style.right = "";
8077 if(pc.bottom == "auto"){
8078 this.dom.style.bottom = "";
8084 fixDisplay : function(){
8085 if(this.getStyle("display") == "none"){
8086 this.setStyle("visibility", "hidden");
8087 this.setStyle("display", this.originalDisplay); // first try reverting to default
8088 if(this.getStyle("display") == "none"){ // if that fails, default to block
8089 this.setStyle("display", "block");
8095 * Quick set left and top adding default units
8096 * @param {String} left The left CSS property value
8097 * @param {String} top The top CSS property value
8098 * @return {Roo.Element} this
8100 setLeftTop : function(left, top){
8101 this.dom.style.left = this.addUnits(left);
8102 this.dom.style.top = this.addUnits(top);
8107 * Move this element relative to its current position.
8108 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8109 * @param {Number} distance How far to move the element in pixels
8110 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8111 * @return {Roo.Element} this
8113 move : function(direction, distance, animate){
8114 var xy = this.getXY();
8115 direction = direction.toLowerCase();
8119 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8123 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8128 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8133 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8140 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8141 * @return {Roo.Element} this
8144 if(!this.isClipped){
8145 this.isClipped = true;
8146 this.originalClip = {
8147 "o": this.getStyle("overflow"),
8148 "x": this.getStyle("overflow-x"),
8149 "y": this.getStyle("overflow-y")
8151 this.setStyle("overflow", "hidden");
8152 this.setStyle("overflow-x", "hidden");
8153 this.setStyle("overflow-y", "hidden");
8159 * Return clipping (overflow) to original clipping before clip() was called
8160 * @return {Roo.Element} this
8162 unclip : function(){
8164 this.isClipped = false;
8165 var o = this.originalClip;
8166 if(o.o){this.setStyle("overflow", o.o);}
8167 if(o.x){this.setStyle("overflow-x", o.x);}
8168 if(o.y){this.setStyle("overflow-y", o.y);}
8175 * Gets the x,y coordinates specified by the anchor position on the element.
8176 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8177 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8178 * {width: (target width), height: (target height)} (defaults to the element's current size)
8179 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8180 * @return {Array} [x, y] An array containing the element's x and y coordinates
8182 getAnchorXY : function(anchor, local, s){
8183 //Passing a different size is useful for pre-calculating anchors,
8184 //especially for anchored animations that change the el size.
8186 var w, h, vp = false;
8189 if(d == document.body || d == document){
8191 w = D.getViewWidth(); h = D.getViewHeight();
8193 w = this.getWidth(); h = this.getHeight();
8196 w = s.width; h = s.height;
8198 var x = 0, y = 0, r = Math.round;
8199 switch((anchor || "tl").toLowerCase()){
8241 var sc = this.getScroll();
8242 return [x + sc.left, y + sc.top];
8244 //Add the element's offset xy
8245 var o = this.getXY();
8246 return [x+o[0], y+o[1]];
8250 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8251 * supported position values.
8252 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8253 * @param {String} position The position to align to.
8254 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8255 * @return {Array} [x, y]
8257 getAlignToXY : function(el, p, o){
8261 throw "Element.alignTo with an element that doesn't exist";
8263 var c = false; //constrain to viewport
8264 var p1 = "", p2 = "";
8271 }else if(p.indexOf("-") == -1){
8274 p = p.toLowerCase();
8275 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8277 throw "Element.alignTo with an invalid alignment " + p;
8279 p1 = m[1]; p2 = m[2]; c = !!m[3];
8281 //Subtract the aligned el's internal xy from the target's offset xy
8282 //plus custom offset to get the aligned el's new offset xy
8283 var a1 = this.getAnchorXY(p1, true);
8284 var a2 = el.getAnchorXY(p2, false);
8285 var x = a2[0] - a1[0] + o[0];
8286 var y = a2[1] - a1[1] + o[1];
8288 //constrain the aligned el to viewport if necessary
8289 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8290 // 5px of margin for ie
8291 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8293 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8294 //perpendicular to the vp border, allow the aligned el to slide on that border,
8295 //otherwise swap the aligned el to the opposite border of the target.
8296 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8297 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8298 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8299 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8302 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8303 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8305 if((x+w) > dw + scrollX){
8306 x = swapX ? r.left-w : dw+scrollX-w;
8309 x = swapX ? r.right : scrollX;
8311 if((y+h) > dh + scrollY){
8312 y = swapY ? r.top-h : dh+scrollY-h;
8315 y = swapY ? r.bottom : scrollY;
8322 getConstrainToXY : function(){
8323 var os = {top:0, left:0, bottom:0, right: 0};
8325 return function(el, local, offsets, proposedXY){
8327 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8329 var vw, vh, vx = 0, vy = 0;
8330 if(el.dom == document.body || el.dom == document){
8331 vw = Roo.lib.Dom.getViewWidth();
8332 vh = Roo.lib.Dom.getViewHeight();
8334 vw = el.dom.clientWidth;
8335 vh = el.dom.clientHeight;
8337 var vxy = el.getXY();
8343 var s = el.getScroll();
8345 vx += offsets.left + s.left;
8346 vy += offsets.top + s.top;
8348 vw -= offsets.right;
8349 vh -= offsets.bottom;
8354 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8355 var x = xy[0], y = xy[1];
8356 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8358 // only move it if it needs it
8361 // first validate right/bottom
8370 // then make sure top/left isn't negative
8379 return moved ? [x, y] : false;
8384 adjustForConstraints : function(xy, parent, offsets){
8385 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8389 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8390 * document it aligns it to the viewport.
8391 * The position parameter is optional, and can be specified in any one of the following formats:
8393 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8394 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8395 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8396 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8397 * <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
8398 * element's anchor point, and the second value is used as the target's anchor point.</li>
8400 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8401 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8402 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8403 * that specified in order to enforce the viewport constraints.
8404 * Following are all of the supported anchor positions:
8407 ----- -----------------------------
8408 tl The top left corner (default)
8409 t The center of the top edge
8410 tr The top right corner
8411 l The center of the left edge
8412 c In the center of the element
8413 r The center of the right edge
8414 bl The bottom left corner
8415 b The center of the bottom edge
8416 br The bottom right corner
8420 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8421 el.alignTo("other-el");
8423 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8424 el.alignTo("other-el", "tr?");
8426 // align the bottom right corner of el with the center left edge of other-el
8427 el.alignTo("other-el", "br-l?");
8429 // align the center of el with the bottom left corner of other-el and
8430 // adjust the x position by -6 pixels (and the y position by 0)
8431 el.alignTo("other-el", "c-bl", [-6, 0]);
8433 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8434 * @param {String} position The position to align to.
8435 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8436 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8437 * @return {Roo.Element} this
8439 alignTo : function(element, position, offsets, animate){
8440 var xy = this.getAlignToXY(element, position, offsets);
8441 this.setXY(xy, this.preanim(arguments, 3));
8446 * Anchors an element to another element and realigns it when the window is resized.
8447 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8448 * @param {String} position The position to align to.
8449 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8450 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8451 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8452 * is a number, it is used as the buffer delay (defaults to 50ms).
8453 * @param {Function} callback The function to call after the animation finishes
8454 * @return {Roo.Element} this
8456 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8457 var action = function(){
8458 this.alignTo(el, alignment, offsets, animate);
8459 Roo.callback(callback, this);
8461 Roo.EventManager.onWindowResize(action, this);
8462 var tm = typeof monitorScroll;
8463 if(tm != 'undefined'){
8464 Roo.EventManager.on(window, 'scroll', action, this,
8465 {buffer: tm == 'number' ? monitorScroll : 50});
8467 action.call(this); // align immediately
8471 * Clears any opacity settings from this element. Required in some cases for IE.
8472 * @return {Roo.Element} this
8474 clearOpacity : function(){
8475 if (window.ActiveXObject) {
8476 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8477 this.dom.style.filter = "";
8480 this.dom.style.opacity = "";
8481 this.dom.style["-moz-opacity"] = "";
8482 this.dom.style["-khtml-opacity"] = "";
8488 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8489 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8490 * @return {Roo.Element} this
8492 hide : function(animate){
8493 this.setVisible(false, this.preanim(arguments, 0));
8498 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8499 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8500 * @return {Roo.Element} this
8502 show : function(animate){
8503 this.setVisible(true, this.preanim(arguments, 0));
8508 * @private Test if size has a unit, otherwise appends the default
8510 addUnits : function(size){
8511 return Roo.Element.addUnits(size, this.defaultUnit);
8515 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8516 * @return {Roo.Element} this
8518 beginMeasure : function(){
8520 if(el.offsetWidth || el.offsetHeight){
8521 return this; // offsets work already
8524 var p = this.dom, b = document.body; // start with this element
8525 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8526 var pe = Roo.get(p);
8527 if(pe.getStyle('display') == 'none'){
8528 changed.push({el: p, visibility: pe.getStyle("visibility")});
8529 p.style.visibility = "hidden";
8530 p.style.display = "block";
8534 this._measureChanged = changed;
8540 * Restores displays to before beginMeasure was called
8541 * @return {Roo.Element} this
8543 endMeasure : function(){
8544 var changed = this._measureChanged;
8546 for(var i = 0, len = changed.length; i < len; i++) {
8548 r.el.style.visibility = r.visibility;
8549 r.el.style.display = "none";
8551 this._measureChanged = null;
8557 * Update the innerHTML of this element, optionally searching for and processing scripts
8558 * @param {String} html The new HTML
8559 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8560 * @param {Function} callback For async script loading you can be noticed when the update completes
8561 * @return {Roo.Element} this
8563 update : function(html, loadScripts, callback){
8564 if(typeof html == "undefined"){
8567 if(loadScripts !== true){
8568 this.dom.innerHTML = html;
8569 if(typeof callback == "function"){
8577 html += '<span id="' + id + '"></span>';
8579 E.onAvailable(id, function(){
8580 var hd = document.getElementsByTagName("head")[0];
8581 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8582 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8583 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8586 while(match = re.exec(html)){
8587 var attrs = match[1];
8588 var srcMatch = attrs ? attrs.match(srcRe) : false;
8589 if(srcMatch && srcMatch[2]){
8590 var s = document.createElement("script");
8591 s.src = srcMatch[2];
8592 var typeMatch = attrs.match(typeRe);
8593 if(typeMatch && typeMatch[2]){
8594 s.type = typeMatch[2];
8597 }else if(match[2] && match[2].length > 0){
8598 if(window.execScript) {
8599 window.execScript(match[2]);
8607 window.eval(match[2]);
8611 var el = document.getElementById(id);
8612 if(el){el.parentNode.removeChild(el);}
8613 if(typeof callback == "function"){
8617 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8622 * Direct access to the UpdateManager update() method (takes the same parameters).
8623 * @param {String/Function} url The url for this request or a function to call to get the url
8624 * @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}
8625 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8626 * @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.
8627 * @return {Roo.Element} this
8630 var um = this.getUpdateManager();
8631 um.update.apply(um, arguments);
8636 * Gets this element's UpdateManager
8637 * @return {Roo.UpdateManager} The UpdateManager
8639 getUpdateManager : function(){
8640 if(!this.updateManager){
8641 this.updateManager = new Roo.UpdateManager(this);
8643 return this.updateManager;
8647 * Disables text selection for this element (normalized across browsers)
8648 * @return {Roo.Element} this
8650 unselectable : function(){
8651 this.dom.unselectable = "on";
8652 this.swallowEvent("selectstart", true);
8653 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8654 this.addClass("x-unselectable");
8659 * Calculates the x, y to center this element on the screen
8660 * @return {Array} The x, y values [x, y]
8662 getCenterXY : function(){
8663 return this.getAlignToXY(document, 'c-c');
8667 * Centers the Element in either the viewport, or another Element.
8668 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8670 center : function(centerIn){
8671 this.alignTo(centerIn || document, 'c-c');
8676 * Tests various css rules/browsers to determine if this element uses a border box
8679 isBorderBox : function(){
8680 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8684 * Return a box {x, y, width, height} that can be used to set another elements
8685 * size/location to match this element.
8686 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8687 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8688 * @return {Object} box An object in the format {x, y, width, height}
8690 getBox : function(contentBox, local){
8695 var left = parseInt(this.getStyle("left"), 10) || 0;
8696 var top = parseInt(this.getStyle("top"), 10) || 0;
8699 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8701 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8703 var l = this.getBorderWidth("l")+this.getPadding("l");
8704 var r = this.getBorderWidth("r")+this.getPadding("r");
8705 var t = this.getBorderWidth("t")+this.getPadding("t");
8706 var b = this.getBorderWidth("b")+this.getPadding("b");
8707 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)};
8709 bx.right = bx.x + bx.width;
8710 bx.bottom = bx.y + bx.height;
8715 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8716 for more information about the sides.
8717 * @param {String} sides
8720 getFrameWidth : function(sides, onlyContentBox){
8721 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8725 * 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.
8726 * @param {Object} box The box to fill {x, y, width, height}
8727 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8728 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8729 * @return {Roo.Element} this
8731 setBox : function(box, adjust, animate){
8732 var w = box.width, h = box.height;
8733 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8734 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8735 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8737 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8742 * Forces the browser to repaint this element
8743 * @return {Roo.Element} this
8745 repaint : function(){
8747 this.addClass("x-repaint");
8748 setTimeout(function(){
8749 Roo.get(dom).removeClass("x-repaint");
8755 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8756 * then it returns the calculated width of the sides (see getPadding)
8757 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8758 * @return {Object/Number}
8760 getMargins : function(side){
8763 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8764 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8765 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8766 right: parseInt(this.getStyle("margin-right"), 10) || 0
8769 return this.addStyles(side, El.margins);
8774 addStyles : function(sides, styles){
8776 for(var i = 0, len = sides.length; i < len; i++){
8777 v = this.getStyle(styles[sides.charAt(i)]);
8779 w = parseInt(v, 10);
8787 * Creates a proxy element of this element
8788 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8789 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8790 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8791 * @return {Roo.Element} The new proxy element
8793 createProxy : function(config, renderTo, matchBox){
8795 renderTo = Roo.getDom(renderTo);
8797 renderTo = document.body;
8799 config = typeof config == "object" ?
8800 config : {tag : "div", cls: config};
8801 var proxy = Roo.DomHelper.append(renderTo, config, true);
8803 proxy.setBox(this.getBox());
8809 * Puts a mask over this element to disable user interaction. Requires core.css.
8810 * This method can only be applied to elements which accept child nodes.
8811 * @param {String} msg (optional) A message to display in the mask
8812 * @param {String} msgCls (optional) A css class to apply to the msg element
8813 * @return {Element} The mask element
8815 mask : function(msg, msgCls){
8816 if(this.getStyle("position") == "static"){
8817 this.setStyle("position", "relative");
8820 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8822 this.addClass("x-masked");
8823 this._mask.setDisplayed(true);
8824 if(typeof msg == 'string'){
8826 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8828 var mm = this._maskMsg;
8829 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8830 mm.dom.firstChild.innerHTML = msg;
8831 mm.setDisplayed(true);
8834 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8835 this._mask.setHeight(this.getHeight());
8841 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8842 * it is cached for reuse.
8844 unmask : function(removeEl){
8846 if(removeEl === true){
8847 this._mask.remove();
8850 this._maskMsg.remove();
8851 delete this._maskMsg;
8854 this._mask.setDisplayed(false);
8856 this._maskMsg.setDisplayed(false);
8860 this.removeClass("x-masked");
8864 * Returns true if this element is masked
8867 isMasked : function(){
8868 return this._mask && this._mask.isVisible();
8872 * Creates an iframe shim for this element to keep selects and other windowed objects from
8874 * @return {Roo.Element} The new shim element
8876 createShim : function(){
8877 var el = document.createElement('iframe');
8878 el.frameBorder = 'no';
8879 el.className = 'roo-shim';
8880 if(Roo.isIE && Roo.isSecure){
8881 el.src = Roo.SSL_SECURE_URL;
8883 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8884 shim.autoBoxAdjust = false;
8889 * Removes this element from the DOM and deletes it from the cache
8891 remove : function(){
8892 if(this.dom.parentNode){
8893 this.dom.parentNode.removeChild(this.dom);
8895 delete El.cache[this.dom.id];
8899 * Sets up event handlers to add and remove a css class when the mouse is over this element
8900 * @param {String} className
8901 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8902 * mouseout events for children elements
8903 * @return {Roo.Element} this
8905 addClassOnOver : function(className, preventFlicker){
8906 this.on("mouseover", function(){
8907 Roo.fly(this, '_internal').addClass(className);
8909 var removeFn = function(e){
8910 if(preventFlicker !== true || !e.within(this, true)){
8911 Roo.fly(this, '_internal').removeClass(className);
8914 this.on("mouseout", removeFn, this.dom);
8919 * Sets up event handlers to add and remove a css class when this element has the focus
8920 * @param {String} className
8921 * @return {Roo.Element} this
8923 addClassOnFocus : function(className){
8924 this.on("focus", function(){
8925 Roo.fly(this, '_internal').addClass(className);
8927 this.on("blur", function(){
8928 Roo.fly(this, '_internal').removeClass(className);
8933 * 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)
8934 * @param {String} className
8935 * @return {Roo.Element} this
8937 addClassOnClick : function(className){
8939 this.on("mousedown", function(){
8940 Roo.fly(dom, '_internal').addClass(className);
8941 var d = Roo.get(document);
8942 var fn = function(){
8943 Roo.fly(dom, '_internal').removeClass(className);
8944 d.removeListener("mouseup", fn);
8946 d.on("mouseup", fn);
8952 * Stops the specified event from bubbling and optionally prevents the default action
8953 * @param {String} eventName
8954 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8955 * @return {Roo.Element} this
8957 swallowEvent : function(eventName, preventDefault){
8958 var fn = function(e){
8959 e.stopPropagation();
8964 if(eventName instanceof Array){
8965 for(var i = 0, len = eventName.length; i < len; i++){
8966 this.on(eventName[i], fn);
8970 this.on(eventName, fn);
8977 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8980 * Sizes this element to its parent element's dimensions performing
8981 * neccessary box adjustments.
8982 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8983 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8984 * @return {Roo.Element} this
8986 fitToParent : function(monitorResize, targetParent) {
8987 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8988 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8989 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8992 var p = Roo.get(targetParent || this.dom.parentNode);
8993 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8994 if (monitorResize === true) {
8995 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8996 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9002 * Gets the next sibling, skipping text nodes
9003 * @return {HTMLElement} The next sibling or null
9005 getNextSibling : function(){
9006 var n = this.dom.nextSibling;
9007 while(n && n.nodeType != 1){
9014 * Gets the previous sibling, skipping text nodes
9015 * @return {HTMLElement} The previous sibling or null
9017 getPrevSibling : function(){
9018 var n = this.dom.previousSibling;
9019 while(n && n.nodeType != 1){
9020 n = n.previousSibling;
9027 * Appends the passed element(s) to this element
9028 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9029 * @return {Roo.Element} this
9031 appendChild: function(el){
9038 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9039 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9040 * automatically generated with the specified attributes.
9041 * @param {HTMLElement} insertBefore (optional) a child element of this element
9042 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9043 * @return {Roo.Element} The new child element
9045 createChild: function(config, insertBefore, returnDom){
9046 config = config || {tag:'div'};
9048 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9050 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9054 * Appends this element to the passed element
9055 * @param {String/HTMLElement/Element} el The new parent element
9056 * @return {Roo.Element} this
9058 appendTo: function(el){
9059 el = Roo.getDom(el);
9060 el.appendChild(this.dom);
9065 * Inserts this element before the passed element in the DOM
9066 * @param {String/HTMLElement/Element} el The element to insert before
9067 * @return {Roo.Element} this
9069 insertBefore: function(el){
9070 el = Roo.getDom(el);
9071 el.parentNode.insertBefore(this.dom, el);
9076 * Inserts this element after the passed element in the DOM
9077 * @param {String/HTMLElement/Element} el The element to insert after
9078 * @return {Roo.Element} this
9080 insertAfter: function(el){
9081 el = Roo.getDom(el);
9082 el.parentNode.insertBefore(this.dom, el.nextSibling);
9087 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9088 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9089 * @return {Roo.Element} The new child
9091 insertFirst: function(el, returnDom){
9093 if(typeof el == 'object' && !el.nodeType){ // dh config
9094 return this.createChild(el, this.dom.firstChild, returnDom);
9096 el = Roo.getDom(el);
9097 this.dom.insertBefore(el, this.dom.firstChild);
9098 return !returnDom ? Roo.get(el) : el;
9103 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9104 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9105 * @param {String} where (optional) 'before' or 'after' defaults to before
9106 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9107 * @return {Roo.Element} the inserted Element
9109 insertSibling: function(el, where, returnDom){
9110 where = where ? where.toLowerCase() : 'before';
9112 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9114 if(typeof el == 'object' && !el.nodeType){ // dh config
9115 if(where == 'after' && !this.dom.nextSibling){
9116 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9118 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9122 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9123 where == 'before' ? this.dom : this.dom.nextSibling);
9132 * Creates and wraps this element with another element
9133 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9134 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9135 * @return {HTMLElement/Element} The newly created wrapper element
9137 wrap: function(config, returnDom){
9139 config = {tag: "div"};
9141 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9142 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9147 * Replaces the passed element with this element
9148 * @param {String/HTMLElement/Element} el The element to replace
9149 * @return {Roo.Element} this
9151 replace: function(el){
9153 this.insertBefore(el);
9159 * Inserts an html fragment into this element
9160 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9161 * @param {String} html The HTML fragment
9162 * @param {Boolean} returnEl True to return an Roo.Element
9163 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9165 insertHtml : function(where, html, returnEl){
9166 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9167 return returnEl ? Roo.get(el) : el;
9171 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9172 * @param {Object} o The object with the attributes
9173 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9174 * @return {Roo.Element} this
9176 set : function(o, useSet){
9178 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9180 if(attr == "style" || typeof o[attr] == "function") continue;
9182 el.className = o["cls"];
9184 if(useSet) el.setAttribute(attr, o[attr]);
9185 else el[attr] = o[attr];
9189 Roo.DomHelper.applyStyles(el, o.style);
9195 * Convenience method for constructing a KeyMap
9196 * @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:
9197 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9198 * @param {Function} fn The function to call
9199 * @param {Object} scope (optional) The scope of the function
9200 * @return {Roo.KeyMap} The KeyMap created
9202 addKeyListener : function(key, fn, scope){
9204 if(typeof key != "object" || key instanceof Array){
9220 return new Roo.KeyMap(this, config);
9224 * Creates a KeyMap for this element
9225 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9226 * @return {Roo.KeyMap} The KeyMap created
9228 addKeyMap : function(config){
9229 return new Roo.KeyMap(this, config);
9233 * Returns true if this element is scrollable.
9236 isScrollable : function(){
9238 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9242 * 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().
9243 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9244 * @param {Number} value The new scroll value
9245 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9246 * @return {Element} this
9249 scrollTo : function(side, value, animate){
9250 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9252 this.dom[prop] = value;
9254 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9255 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9261 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9262 * within this element's scrollable range.
9263 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9264 * @param {Number} distance How far to scroll the element in pixels
9265 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9266 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9267 * was scrolled as far as it could go.
9269 scroll : function(direction, distance, animate){
9270 if(!this.isScrollable()){
9274 var l = el.scrollLeft, t = el.scrollTop;
9275 var w = el.scrollWidth, h = el.scrollHeight;
9276 var cw = el.clientWidth, ch = el.clientHeight;
9277 direction = direction.toLowerCase();
9278 var scrolled = false;
9279 var a = this.preanim(arguments, 2);
9284 var v = Math.min(l + distance, w-cw);
9285 this.scrollTo("left", v, a);
9292 var v = Math.max(l - distance, 0);
9293 this.scrollTo("left", v, a);
9301 var v = Math.max(t - distance, 0);
9302 this.scrollTo("top", v, a);
9310 var v = Math.min(t + distance, h-ch);
9311 this.scrollTo("top", v, a);
9320 * Translates the passed page coordinates into left/top css values for this element
9321 * @param {Number/Array} x The page x or an array containing [x, y]
9322 * @param {Number} y The page y
9323 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9325 translatePoints : function(x, y){
9326 if(typeof x == 'object' || x instanceof Array){
9329 var p = this.getStyle('position');
9330 var o = this.getXY();
9332 var l = parseInt(this.getStyle('left'), 10);
9333 var t = parseInt(this.getStyle('top'), 10);
9336 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9339 t = (p == "relative") ? 0 : this.dom.offsetTop;
9342 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9346 * Returns the current scroll position of the element.
9347 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9349 getScroll : function(){
9350 var d = this.dom, doc = document;
9351 if(d == doc || d == doc.body){
9352 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9353 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9354 return {left: l, top: t};
9356 return {left: d.scrollLeft, top: d.scrollTop};
9361 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9362 * are convert to standard 6 digit hex color.
9363 * @param {String} attr The css attribute
9364 * @param {String} defaultValue The default value to use when a valid color isn't found
9365 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9368 getColor : function(attr, defaultValue, prefix){
9369 var v = this.getStyle(attr);
9370 if(!v || v == "transparent" || v == "inherit") {
9371 return defaultValue;
9373 var color = typeof prefix == "undefined" ? "#" : prefix;
9374 if(v.substr(0, 4) == "rgb("){
9375 var rvs = v.slice(4, v.length -1).split(",");
9376 for(var i = 0; i < 3; i++){
9377 var h = parseInt(rvs[i]).toString(16);
9384 if(v.substr(0, 1) == "#"){
9386 for(var i = 1; i < 4; i++){
9387 var c = v.charAt(i);
9390 }else if(v.length == 7){
9391 color += v.substr(1);
9395 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9399 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9400 * gradient background, rounded corners and a 4-way shadow.
9401 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9402 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9403 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9404 * @return {Roo.Element} this
9406 boxWrap : function(cls){
9407 cls = cls || 'x-box';
9408 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9409 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9414 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9415 * @param {String} namespace The namespace in which to look for the attribute
9416 * @param {String} name The attribute name
9417 * @return {String} The attribute value
9419 getAttributeNS : Roo.isIE ? function(ns, name){
9421 var type = typeof d[ns+":"+name];
9422 if(type != 'undefined' && type != 'unknown'){
9423 return d[ns+":"+name];
9426 } : function(ns, name){
9428 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9432 var ep = El.prototype;
9435 * Appends an event handler (Shorthand for addListener)
9436 * @param {String} eventName The type of event to append
9437 * @param {Function} fn The method the event invokes
9438 * @param {Object} scope (optional) The scope (this object) of the fn
9439 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9442 ep.on = ep.addListener;
9444 ep.mon = ep.addListener;
9447 * Removes an event handler from this element (shorthand for removeListener)
9448 * @param {String} eventName the type of event to remove
9449 * @param {Function} fn the method the event invokes
9450 * @return {Roo.Element} this
9453 ep.un = ep.removeListener;
9456 * true to automatically adjust width and height settings for box-model issues (default to true)
9458 ep.autoBoxAdjust = true;
9461 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9464 El.addUnits = function(v, defaultUnit){
9465 if(v === "" || v == "auto"){
9468 if(v === undefined){
9471 if(typeof v == "number" || !El.unitPattern.test(v)){
9472 return v + (defaultUnit || 'px');
9477 // special markup used throughout Roo when box wrapping elements
9478 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>';
9480 * Visibility mode constant - Use visibility to hide element
9486 * Visibility mode constant - Use display to hide element
9492 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9493 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9494 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9506 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9507 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9508 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9509 * @return {Element} The Element object
9512 El.get = function(el){
9514 if(!el){ return null; }
9515 if(typeof el == "string"){ // element id
9516 if(!(elm = document.getElementById(el))){
9519 if(ex = El.cache[el]){
9522 ex = El.cache[el] = new El(elm);
9525 }else if(el.tagName){ // dom element
9529 if(ex = El.cache[id]){
9532 ex = El.cache[id] = new El(el);
9535 }else if(el instanceof El){
9537 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9538 // catch case where it hasn't been appended
9539 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9542 }else if(el.isComposite){
9544 }else if(el instanceof Array){
9545 return El.select(el);
9546 }else if(el == document){
9547 // create a bogus element object representing the document object
9549 var f = function(){};
9550 f.prototype = El.prototype;
9552 docEl.dom = document;
9560 El.uncache = function(el){
9561 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9563 delete El.cache[a[i].id || a[i]];
9569 // Garbage collection - uncache elements/purge listeners on orphaned elements
9570 // so we don't hold a reference and cause the browser to retain them
9571 El.garbageCollect = function(){
9572 if(!Roo.enableGarbageCollector){
9573 clearInterval(El.collectorThread);
9576 for(var eid in El.cache){
9577 var el = El.cache[eid], d = el.dom;
9578 // -------------------------------------------------------
9579 // Determining what is garbage:
9580 // -------------------------------------------------------
9582 // dom node is null, definitely garbage
9583 // -------------------------------------------------------
9585 // no parentNode == direct orphan, definitely garbage
9586 // -------------------------------------------------------
9587 // !d.offsetParent && !document.getElementById(eid)
9588 // display none elements have no offsetParent so we will
9589 // also try to look it up by it's id. However, check
9590 // offsetParent first so we don't do unneeded lookups.
9591 // This enables collection of elements that are not orphans
9592 // directly, but somewhere up the line they have an orphan
9594 // -------------------------------------------------------
9595 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9596 delete El.cache[eid];
9597 if(d && Roo.enableListenerCollection){
9603 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9607 El.Flyweight = function(dom){
9610 El.Flyweight.prototype = El.prototype;
9612 El._flyweights = {};
9614 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9615 * the dom node can be overwritten by other code.
9616 * @param {String/HTMLElement} el The dom node or id
9617 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9618 * prevent conflicts (e.g. internally Roo uses "_internal")
9620 * @return {Element} The shared Element object
9622 El.fly = function(el, named){
9623 named = named || '_global';
9624 el = Roo.getDom(el);
9628 if(!El._flyweights[named]){
9629 El._flyweights[named] = new El.Flyweight();
9631 El._flyweights[named].dom = el;
9632 return El._flyweights[named];
9636 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9637 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9638 * Shorthand of {@link Roo.Element#get}
9639 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9640 * @return {Element} The Element object
9646 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9647 * the dom node can be overwritten by other code.
9648 * Shorthand of {@link Roo.Element#fly}
9649 * @param {String/HTMLElement} el The dom node or id
9650 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9651 * prevent conflicts (e.g. internally Roo uses "_internal")
9653 * @return {Element} The shared Element object
9659 // speedy lookup for elements never to box adjust
9660 var noBoxAdjust = Roo.isStrict ? {
9663 input:1, select:1, textarea:1
9665 if(Roo.isIE || Roo.isGecko){
9666 noBoxAdjust['button'] = 1;
9670 Roo.EventManager.on(window, 'unload', function(){
9672 delete El._flyweights;
9680 Roo.Element.selectorFunction = Roo.DomQuery.select;
9683 Roo.Element.select = function(selector, unique, root){
9685 if(typeof selector == "string"){
9686 els = Roo.Element.selectorFunction(selector, root);
9687 }else if(selector.length !== undefined){
9690 throw "Invalid selector";
9692 if(unique === true){
9693 return new Roo.CompositeElement(els);
9695 return new Roo.CompositeElementLite(els);
9699 * Selects elements based on the passed CSS selector to enable working on them as 1.
9700 * @param {String/Array} selector The CSS selector or an array of elements
9701 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9702 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9703 * @return {CompositeElementLite/CompositeElement}
9707 Roo.select = Roo.Element.select;
9724 * Ext JS Library 1.1.1
9725 * Copyright(c) 2006-2007, Ext JS, LLC.
9727 * Originally Released Under LGPL - original licence link has changed is not relivant.
9730 * <script type="text/javascript">
9735 //Notifies Element that fx methods are available
9736 Roo.enableFx = true;
9740 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9741 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9742 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9743 * Element effects to work.</p><br/>
9745 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9746 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9747 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9748 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9749 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9750 * expected results and should be done with care.</p><br/>
9752 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9753 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9756 ----- -----------------------------
9757 tl The top left corner
9758 t The center of the top edge
9759 tr The top right corner
9760 l The center of the left edge
9761 r The center of the right edge
9762 bl The bottom left corner
9763 b The center of the bottom edge
9764 br The bottom right corner
9766 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9767 * below are common options that can be passed to any Fx method.</b>
9768 * @cfg {Function} callback A function called when the effect is finished
9769 * @cfg {Object} scope The scope of the effect function
9770 * @cfg {String} easing A valid Easing value for the effect
9771 * @cfg {String} afterCls A css class to apply after the effect
9772 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9773 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9774 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9775 * effects that end with the element being visually hidden, ignored otherwise)
9776 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9777 * a function which returns such a specification that will be applied to the Element after the effect finishes
9778 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9779 * @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
9780 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9784 * Slides the element into view. An anchor point can be optionally passed to set the point of
9785 * origin for the slide effect. This function automatically handles wrapping the element with
9786 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9789 // default: slide the element in from the top
9792 // custom: slide the element in from the right with a 2-second duration
9793 el.slideIn('r', { duration: 2 });
9795 // common config options shown with default values
9801 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9802 * @param {Object} options (optional) Object literal with any of the Fx config options
9803 * @return {Roo.Element} The Element
9805 slideIn : function(anchor, o){
9806 var el = this.getFxEl();
9809 el.queueFx(o, function(){
9811 anchor = anchor || "t";
9813 // fix display to visibility
9816 // restore values after effect
9817 var r = this.getFxRestore();
9818 var b = this.getBox();
9819 // fixed size for slide
9823 var wrap = this.fxWrap(r.pos, o, "hidden");
9825 var st = this.dom.style;
9826 st.visibility = "visible";
9827 st.position = "absolute";
9829 // clear out temp styles after slide and unwrap
9830 var after = function(){
9831 el.fxUnwrap(wrap, r.pos, o);
9833 st.height = r.height;
9836 // time to calc the positions
9837 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9839 switch(anchor.toLowerCase()){
9841 wrap.setSize(b.width, 0);
9842 st.left = st.bottom = "0";
9846 wrap.setSize(0, b.height);
9847 st.right = st.top = "0";
9851 wrap.setSize(0, b.height);
9853 st.left = st.top = "0";
9854 a = {width: bw, points: pt};
9857 wrap.setSize(b.width, 0);
9858 wrap.setY(b.bottom);
9859 st.left = st.top = "0";
9860 a = {height: bh, points: pt};
9864 st.right = st.bottom = "0";
9865 a = {width: bw, height: bh};
9869 wrap.setY(b.y+b.height);
9870 st.right = st.top = "0";
9871 a = {width: bw, height: bh, points: pt};
9875 wrap.setXY([b.right, b.bottom]);
9876 st.left = st.top = "0";
9877 a = {width: bw, height: bh, points: pt};
9881 wrap.setX(b.x+b.width);
9882 st.left = st.bottom = "0";
9883 a = {width: bw, height: bh, points: pt};
9886 this.dom.style.visibility = "visible";
9889 arguments.callee.anim = wrap.fxanim(a,
9899 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9900 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9901 * 'hidden') but block elements will still take up space in the document. The element must be removed
9902 * from the DOM using the 'remove' config option if desired. This function automatically handles
9903 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9906 // default: slide the element out to the top
9909 // custom: slide the element out to the right with a 2-second duration
9910 el.slideOut('r', { duration: 2 });
9912 // common config options shown with default values
9920 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9921 * @param {Object} options (optional) Object literal with any of the Fx config options
9922 * @return {Roo.Element} The Element
9924 slideOut : function(anchor, o){
9925 var el = this.getFxEl();
9928 el.queueFx(o, function(){
9930 anchor = anchor || "t";
9932 // restore values after effect
9933 var r = this.getFxRestore();
9935 var b = this.getBox();
9936 // fixed size for slide
9940 var wrap = this.fxWrap(r.pos, o, "visible");
9942 var st = this.dom.style;
9943 st.visibility = "visible";
9944 st.position = "absolute";
9948 var after = function(){
9950 el.setDisplayed(false);
9955 el.fxUnwrap(wrap, r.pos, o);
9958 st.height = r.height;
9963 var a, zero = {to: 0};
9964 switch(anchor.toLowerCase()){
9966 st.left = st.bottom = "0";
9970 st.right = st.top = "0";
9974 st.left = st.top = "0";
9975 a = {width: zero, points: {to:[b.right, b.y]}};
9978 st.left = st.top = "0";
9979 a = {height: zero, points: {to:[b.x, b.bottom]}};
9982 st.right = st.bottom = "0";
9983 a = {width: zero, height: zero};
9986 st.right = st.top = "0";
9987 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9990 st.left = st.top = "0";
9991 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9994 st.left = st.bottom = "0";
9995 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9999 arguments.callee.anim = wrap.fxanim(a,
10009 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10010 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10011 * The element must be removed from the DOM using the 'remove' config option if desired.
10017 // common config options shown with default values
10025 * @param {Object} options (optional) Object literal with any of the Fx config options
10026 * @return {Roo.Element} The Element
10028 puff : function(o){
10029 var el = this.getFxEl();
10032 el.queueFx(o, function(){
10033 this.clearOpacity();
10036 // restore values after effect
10037 var r = this.getFxRestore();
10038 var st = this.dom.style;
10040 var after = function(){
10042 el.setDisplayed(false);
10049 el.setPositioning(r.pos);
10050 st.width = r.width;
10051 st.height = r.height;
10056 var width = this.getWidth();
10057 var height = this.getHeight();
10059 arguments.callee.anim = this.fxanim({
10060 width : {to: this.adjustWidth(width * 2)},
10061 height : {to: this.adjustHeight(height * 2)},
10062 points : {by: [-(width * .5), -(height * .5)]},
10064 fontSize: {to:200, unit: "%"}
10075 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10076 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10077 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10083 // all config options shown with default values
10091 * @param {Object} options (optional) Object literal with any of the Fx config options
10092 * @return {Roo.Element} The Element
10094 switchOff : function(o){
10095 var el = this.getFxEl();
10098 el.queueFx(o, function(){
10099 this.clearOpacity();
10102 // restore values after effect
10103 var r = this.getFxRestore();
10104 var st = this.dom.style;
10106 var after = function(){
10108 el.setDisplayed(false);
10114 el.setPositioning(r.pos);
10115 st.width = r.width;
10116 st.height = r.height;
10121 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10122 this.clearOpacity();
10126 points:{by:[0, this.getHeight() * .5]}
10127 }, o, 'motion', 0.3, 'easeIn', after);
10128 }).defer(100, this);
10135 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10136 * changed using the "attr" config option) and then fading back to the original color. If no original
10137 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10140 // default: highlight background to yellow
10143 // custom: highlight foreground text to blue for 2 seconds
10144 el.highlight("0000ff", { attr: 'color', duration: 2 });
10146 // common config options shown with default values
10147 el.highlight("ffff9c", {
10148 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10149 endColor: (current color) or "ffffff",
10154 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10155 * @param {Object} options (optional) Object literal with any of the Fx config options
10156 * @return {Roo.Element} The Element
10158 highlight : function(color, o){
10159 var el = this.getFxEl();
10162 el.queueFx(o, function(){
10163 color = color || "ffff9c";
10164 attr = o.attr || "backgroundColor";
10166 this.clearOpacity();
10169 var origColor = this.getColor(attr);
10170 var restoreColor = this.dom.style[attr];
10171 endColor = (o.endColor || origColor) || "ffffff";
10173 var after = function(){
10174 el.dom.style[attr] = restoreColor;
10179 a[attr] = {from: color, to: endColor};
10180 arguments.callee.anim = this.fxanim(a,
10190 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10193 // default: a single light blue ripple
10196 // custom: 3 red ripples lasting 3 seconds total
10197 el.frame("ff0000", 3, { duration: 3 });
10199 // common config options shown with default values
10200 el.frame("C3DAF9", 1, {
10201 duration: 1 //duration of entire animation (not each individual ripple)
10202 // Note: Easing is not configurable and will be ignored if included
10205 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10206 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10207 * @param {Object} options (optional) Object literal with any of the Fx config options
10208 * @return {Roo.Element} The Element
10210 frame : function(color, count, o){
10211 var el = this.getFxEl();
10214 el.queueFx(o, function(){
10215 color = color || "#C3DAF9";
10216 if(color.length == 6){
10217 color = "#" + color;
10219 count = count || 1;
10220 duration = o.duration || 1;
10223 var b = this.getBox();
10224 var animFn = function(){
10225 var proxy = this.createProxy({
10228 visbility:"hidden",
10229 position:"absolute",
10230 "z-index":"35000", // yee haw
10231 border:"0px solid " + color
10234 var scale = Roo.isBorderBox ? 2 : 1;
10236 top:{from:b.y, to:b.y - 20},
10237 left:{from:b.x, to:b.x - 20},
10238 borderWidth:{from:0, to:10},
10239 opacity:{from:1, to:0},
10240 height:{from:b.height, to:(b.height + (20*scale))},
10241 width:{from:b.width, to:(b.width + (20*scale))}
10242 }, duration, function(){
10246 animFn.defer((duration/2)*1000, this);
10257 * Creates a pause before any subsequent queued effects begin. If there are
10258 * no effects queued after the pause it will have no effect.
10263 * @param {Number} seconds The length of time to pause (in seconds)
10264 * @return {Roo.Element} The Element
10266 pause : function(seconds){
10267 var el = this.getFxEl();
10270 el.queueFx(o, function(){
10271 setTimeout(function(){
10273 }, seconds * 1000);
10279 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10280 * using the "endOpacity" config option.
10283 // default: fade in from opacity 0 to 100%
10286 // custom: fade in from opacity 0 to 75% over 2 seconds
10287 el.fadeIn({ endOpacity: .75, duration: 2});
10289 // common config options shown with default values
10291 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10296 * @param {Object} options (optional) Object literal with any of the Fx config options
10297 * @return {Roo.Element} The Element
10299 fadeIn : function(o){
10300 var el = this.getFxEl();
10302 el.queueFx(o, function(){
10303 this.setOpacity(0);
10305 this.dom.style.visibility = 'visible';
10306 var to = o.endOpacity || 1;
10307 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10308 o, null, .5, "easeOut", function(){
10310 this.clearOpacity();
10319 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10320 * using the "endOpacity" config option.
10323 // default: fade out from the element's current opacity to 0
10326 // custom: fade out from the element's current opacity to 25% over 2 seconds
10327 el.fadeOut({ endOpacity: .25, duration: 2});
10329 // common config options shown with default values
10331 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10338 * @param {Object} options (optional) Object literal with any of the Fx config options
10339 * @return {Roo.Element} The Element
10341 fadeOut : function(o){
10342 var el = this.getFxEl();
10344 el.queueFx(o, function(){
10345 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10346 o, null, .5, "easeOut", function(){
10347 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10348 this.dom.style.display = "none";
10350 this.dom.style.visibility = "hidden";
10352 this.clearOpacity();
10360 * Animates the transition of an element's dimensions from a starting height/width
10361 * to an ending height/width.
10364 // change height and width to 100x100 pixels
10365 el.scale(100, 100);
10367 // common config options shown with default values. The height and width will default to
10368 // the element's existing values if passed as null.
10371 [element's height], {
10376 * @param {Number} width The new width (pass undefined to keep the original width)
10377 * @param {Number} height The new height (pass undefined to keep the original height)
10378 * @param {Object} options (optional) Object literal with any of the Fx config options
10379 * @return {Roo.Element} The Element
10381 scale : function(w, h, o){
10382 this.shift(Roo.apply({}, o, {
10390 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10391 * Any of these properties not specified in the config object will not be changed. This effect
10392 * requires that at least one new dimension, position or opacity setting must be passed in on
10393 * the config object in order for the function to have any effect.
10396 // slide the element horizontally to x position 200 while changing the height and opacity
10397 el.shift({ x: 200, height: 50, opacity: .8 });
10399 // common config options shown with default values.
10401 width: [element's width],
10402 height: [element's height],
10403 x: [element's x position],
10404 y: [element's y position],
10405 opacity: [element's opacity],
10410 * @param {Object} options Object literal with any of the Fx config options
10411 * @return {Roo.Element} The Element
10413 shift : function(o){
10414 var el = this.getFxEl();
10416 el.queueFx(o, function(){
10417 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10418 if(w !== undefined){
10419 a.width = {to: this.adjustWidth(w)};
10421 if(h !== undefined){
10422 a.height = {to: this.adjustHeight(h)};
10424 if(x !== undefined || y !== undefined){
10426 x !== undefined ? x : this.getX(),
10427 y !== undefined ? y : this.getY()
10430 if(op !== undefined){
10431 a.opacity = {to: op};
10433 if(o.xy !== undefined){
10434 a.points = {to: o.xy};
10436 arguments.callee.anim = this.fxanim(a,
10437 o, 'motion', .35, "easeOut", function(){
10445 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10446 * ending point of the effect.
10449 // default: slide the element downward while fading out
10452 // custom: slide the element out to the right with a 2-second duration
10453 el.ghost('r', { duration: 2 });
10455 // common config options shown with default values
10463 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10464 * @param {Object} options (optional) Object literal with any of the Fx config options
10465 * @return {Roo.Element} The Element
10467 ghost : function(anchor, o){
10468 var el = this.getFxEl();
10471 el.queueFx(o, function(){
10472 anchor = anchor || "b";
10474 // restore values after effect
10475 var r = this.getFxRestore();
10476 var w = this.getWidth(),
10477 h = this.getHeight();
10479 var st = this.dom.style;
10481 var after = function(){
10483 el.setDisplayed(false);
10489 el.setPositioning(r.pos);
10490 st.width = r.width;
10491 st.height = r.height;
10496 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10497 switch(anchor.toLowerCase()){
10524 arguments.callee.anim = this.fxanim(a,
10534 * Ensures that all effects queued after syncFx is called on the element are
10535 * run concurrently. This is the opposite of {@link #sequenceFx}.
10536 * @return {Roo.Element} The Element
10538 syncFx : function(){
10539 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10548 * Ensures that all effects queued after sequenceFx is called on the element are
10549 * run in sequence. This is the opposite of {@link #syncFx}.
10550 * @return {Roo.Element} The Element
10552 sequenceFx : function(){
10553 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10555 concurrent : false,
10562 nextFx : function(){
10563 var ef = this.fxQueue[0];
10570 * Returns true if the element has any effects actively running or queued, else returns false.
10571 * @return {Boolean} True if element has active effects, else false
10573 hasActiveFx : function(){
10574 return this.fxQueue && this.fxQueue[0];
10578 * Stops any running effects and clears the element's internal effects queue if it contains
10579 * any additional effects that haven't started yet.
10580 * @return {Roo.Element} The Element
10582 stopFx : function(){
10583 if(this.hasActiveFx()){
10584 var cur = this.fxQueue[0];
10585 if(cur && cur.anim && cur.anim.isAnimated()){
10586 this.fxQueue = [cur]; // clear out others
10587 cur.anim.stop(true);
10594 beforeFx : function(o){
10595 if(this.hasActiveFx() && !o.concurrent){
10606 * Returns true if the element is currently blocking so that no other effect can be queued
10607 * until this effect is finished, else returns false if blocking is not set. This is commonly
10608 * used to ensure that an effect initiated by a user action runs to completion prior to the
10609 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10610 * @return {Boolean} True if blocking, else false
10612 hasFxBlock : function(){
10613 var q = this.fxQueue;
10614 return q && q[0] && q[0].block;
10618 queueFx : function(o, fn){
10622 if(!this.hasFxBlock()){
10623 Roo.applyIf(o, this.fxDefaults);
10625 var run = this.beforeFx(o);
10626 fn.block = o.block;
10627 this.fxQueue.push(fn);
10639 fxWrap : function(pos, o, vis){
10641 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10644 wrapXY = this.getXY();
10646 var div = document.createElement("div");
10647 div.style.visibility = vis;
10648 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10649 wrap.setPositioning(pos);
10650 if(wrap.getStyle("position") == "static"){
10651 wrap.position("relative");
10653 this.clearPositioning('auto');
10655 wrap.dom.appendChild(this.dom);
10657 wrap.setXY(wrapXY);
10664 fxUnwrap : function(wrap, pos, o){
10665 this.clearPositioning();
10666 this.setPositioning(pos);
10668 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10674 getFxRestore : function(){
10675 var st = this.dom.style;
10676 return {pos: this.getPositioning(), width: st.width, height : st.height};
10680 afterFx : function(o){
10682 this.applyStyles(o.afterStyle);
10685 this.addClass(o.afterCls);
10687 if(o.remove === true){
10690 Roo.callback(o.callback, o.scope, [this]);
10692 this.fxQueue.shift();
10698 getFxEl : function(){ // support for composite element fx
10699 return Roo.get(this.dom);
10703 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10704 animType = animType || 'run';
10706 var anim = Roo.lib.Anim[animType](
10708 (opt.duration || defaultDur) || .35,
10709 (opt.easing || defaultEase) || 'easeOut',
10711 Roo.callback(cb, this);
10720 // backwords compat
10721 Roo.Fx.resize = Roo.Fx.scale;
10723 //When included, Roo.Fx is automatically applied to Element so that all basic
10724 //effects are available directly via the Element API
10725 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10727 * Ext JS Library 1.1.1
10728 * Copyright(c) 2006-2007, Ext JS, LLC.
10730 * Originally Released Under LGPL - original licence link has changed is not relivant.
10733 * <script type="text/javascript">
10738 * @class Roo.CompositeElement
10739 * Standard composite class. Creates a Roo.Element for every element in the collection.
10741 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10742 * actions will be performed on all the elements in this collection.</b>
10744 * All methods return <i>this</i> and can be chained.
10746 var els = Roo.select("#some-el div.some-class", true);
10747 // or select directly from an existing element
10748 var el = Roo.get('some-el');
10749 el.select('div.some-class', true);
10751 els.setWidth(100); // all elements become 100 width
10752 els.hide(true); // all elements fade out and hide
10754 els.setWidth(100).hide(true);
10757 Roo.CompositeElement = function(els){
10758 this.elements = [];
10759 this.addElements(els);
10761 Roo.CompositeElement.prototype = {
10763 addElements : function(els){
10764 if(!els) return this;
10765 if(typeof els == "string"){
10766 els = Roo.Element.selectorFunction(els);
10768 var yels = this.elements;
10769 var index = yels.length-1;
10770 for(var i = 0, len = els.length; i < len; i++) {
10771 yels[++index] = Roo.get(els[i]);
10777 * Clears this composite and adds the elements returned by the passed selector.
10778 * @param {String/Array} els A string CSS selector, an array of elements or an element
10779 * @return {CompositeElement} this
10781 fill : function(els){
10782 this.elements = [];
10788 * Filters this composite to only elements that match the passed selector.
10789 * @param {String} selector A string CSS selector
10790 * @return {CompositeElement} this
10792 filter : function(selector){
10794 this.each(function(el){
10795 if(el.is(selector)){
10796 els[els.length] = el.dom;
10803 invoke : function(fn, args){
10804 var els = this.elements;
10805 for(var i = 0, len = els.length; i < len; i++) {
10806 Roo.Element.prototype[fn].apply(els[i], args);
10811 * Adds elements to this composite.
10812 * @param {String/Array} els A string CSS selector, an array of elements or an element
10813 * @return {CompositeElement} this
10815 add : function(els){
10816 if(typeof els == "string"){
10817 this.addElements(Roo.Element.selectorFunction(els));
10818 }else if(els.length !== undefined){
10819 this.addElements(els);
10821 this.addElements([els]);
10826 * Calls the passed function passing (el, this, index) for each element in this composite.
10827 * @param {Function} fn The function to call
10828 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10829 * @return {CompositeElement} this
10831 each : function(fn, scope){
10832 var els = this.elements;
10833 for(var i = 0, len = els.length; i < len; i++){
10834 if(fn.call(scope || els[i], els[i], this, i) === false) {
10842 * Returns the Element object at the specified index
10843 * @param {Number} index
10844 * @return {Roo.Element}
10846 item : function(index){
10847 return this.elements[index] || null;
10851 * Returns the first Element
10852 * @return {Roo.Element}
10854 first : function(){
10855 return this.item(0);
10859 * Returns the last Element
10860 * @return {Roo.Element}
10863 return this.item(this.elements.length-1);
10867 * Returns the number of elements in this composite
10870 getCount : function(){
10871 return this.elements.length;
10875 * Returns true if this composite contains the passed element
10878 contains : function(el){
10879 return this.indexOf(el) !== -1;
10883 * Returns true if this composite contains the passed element
10886 indexOf : function(el){
10887 return this.elements.indexOf(Roo.get(el));
10892 * Removes the specified element(s).
10893 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10894 * or an array of any of those.
10895 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10896 * @return {CompositeElement} this
10898 removeElement : function(el, removeDom){
10899 if(el instanceof Array){
10900 for(var i = 0, len = el.length; i < len; i++){
10901 this.removeElement(el[i]);
10905 var index = typeof el == 'number' ? el : this.indexOf(el);
10908 var d = this.elements[index];
10912 d.parentNode.removeChild(d);
10915 this.elements.splice(index, 1);
10921 * Replaces the specified element with the passed element.
10922 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10924 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10925 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10926 * @return {CompositeElement} this
10928 replaceElement : function(el, replacement, domReplace){
10929 var index = typeof el == 'number' ? el : this.indexOf(el);
10932 this.elements[index].replaceWith(replacement);
10934 this.elements.splice(index, 1, Roo.get(replacement))
10941 * Removes all elements.
10943 clear : function(){
10944 this.elements = [];
10948 Roo.CompositeElement.createCall = function(proto, fnName){
10949 if(!proto[fnName]){
10950 proto[fnName] = function(){
10951 return this.invoke(fnName, arguments);
10955 for(var fnName in Roo.Element.prototype){
10956 if(typeof Roo.Element.prototype[fnName] == "function"){
10957 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10963 * Ext JS Library 1.1.1
10964 * Copyright(c) 2006-2007, Ext JS, LLC.
10966 * Originally Released Under LGPL - original licence link has changed is not relivant.
10969 * <script type="text/javascript">
10973 * @class Roo.CompositeElementLite
10974 * @extends Roo.CompositeElement
10975 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10977 var els = Roo.select("#some-el div.some-class");
10978 // or select directly from an existing element
10979 var el = Roo.get('some-el');
10980 el.select('div.some-class');
10982 els.setWidth(100); // all elements become 100 width
10983 els.hide(true); // all elements fade out and hide
10985 els.setWidth(100).hide(true);
10986 </code></pre><br><br>
10987 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10988 * actions will be performed on all the elements in this collection.</b>
10990 Roo.CompositeElementLite = function(els){
10991 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10992 this.el = new Roo.Element.Flyweight();
10994 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10995 addElements : function(els){
10997 if(els instanceof Array){
10998 this.elements = this.elements.concat(els);
11000 var yels = this.elements;
11001 var index = yels.length-1;
11002 for(var i = 0, len = els.length; i < len; i++) {
11003 yels[++index] = els[i];
11009 invoke : function(fn, args){
11010 var els = this.elements;
11012 for(var i = 0, len = els.length; i < len; i++) {
11014 Roo.Element.prototype[fn].apply(el, args);
11019 * Returns a flyweight Element of the dom element object at the specified index
11020 * @param {Number} index
11021 * @return {Roo.Element}
11023 item : function(index){
11024 if(!this.elements[index]){
11027 this.el.dom = this.elements[index];
11031 // fixes scope with flyweight
11032 addListener : function(eventName, handler, scope, opt){
11033 var els = this.elements;
11034 for(var i = 0, len = els.length; i < len; i++) {
11035 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11041 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11042 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11043 * a reference to the dom node, use el.dom.</b>
11044 * @param {Function} fn The function to call
11045 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11046 * @return {CompositeElement} this
11048 each : function(fn, scope){
11049 var els = this.elements;
11051 for(var i = 0, len = els.length; i < len; i++){
11053 if(fn.call(scope || el, el, this, i) === false){
11060 indexOf : function(el){
11061 return this.elements.indexOf(Roo.getDom(el));
11064 replaceElement : function(el, replacement, domReplace){
11065 var index = typeof el == 'number' ? el : this.indexOf(el);
11067 replacement = Roo.getDom(replacement);
11069 var d = this.elements[index];
11070 d.parentNode.insertBefore(replacement, d);
11071 d.parentNode.removeChild(d);
11073 this.elements.splice(index, 1, replacement);
11078 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11082 * Ext JS Library 1.1.1
11083 * Copyright(c) 2006-2007, Ext JS, LLC.
11085 * Originally Released Under LGPL - original licence link has changed is not relivant.
11088 * <script type="text/javascript">
11094 * @class Roo.data.Connection
11095 * @extends Roo.util.Observable
11096 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11097 * either to a configured URL, or to a URL specified at request time.<br><br>
11099 * Requests made by this class are asynchronous, and will return immediately. No data from
11100 * the server will be available to the statement immediately following the {@link #request} call.
11101 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11103 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11104 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11105 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11106 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11107 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11108 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11109 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11110 * standard DOM methods.
11112 * @param {Object} config a configuration object.
11114 Roo.data.Connection = function(config){
11115 Roo.apply(this, config);
11118 * @event beforerequest
11119 * Fires before a network request is made to retrieve a data object.
11120 * @param {Connection} conn This Connection object.
11121 * @param {Object} options The options config object passed to the {@link #request} method.
11123 "beforerequest" : true,
11125 * @event requestcomplete
11126 * Fires if the request was successfully completed.
11127 * @param {Connection} conn This Connection object.
11128 * @param {Object} response The XHR object containing the response data.
11129 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11130 * @param {Object} options The options config object passed to the {@link #request} method.
11132 "requestcomplete" : true,
11134 * @event requestexception
11135 * Fires if an error HTTP status was returned from the server.
11136 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11137 * @param {Connection} conn This Connection object.
11138 * @param {Object} response The XHR object containing the response data.
11139 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11140 * @param {Object} options The options config object passed to the {@link #request} method.
11142 "requestexception" : true
11144 Roo.data.Connection.superclass.constructor.call(this);
11147 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11149 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11152 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11153 * extra parameters to each request made by this object. (defaults to undefined)
11156 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11157 * to each request made by this object. (defaults to undefined)
11160 * @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)
11163 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11167 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11173 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11176 disableCaching: true,
11179 * Sends an HTTP request to a remote server.
11180 * @param {Object} options An object which may contain the following properties:<ul>
11181 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11182 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11183 * request, a url encoded string or a function to call to get either.</li>
11184 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11185 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11186 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11187 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11188 * <li>options {Object} The parameter to the request call.</li>
11189 * <li>success {Boolean} True if the request succeeded.</li>
11190 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11192 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11193 * The callback is passed the following parameters:<ul>
11194 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11195 * <li>options {Object} The parameter to the request call.</li>
11197 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11198 * The callback is passed the following parameters:<ul>
11199 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11200 * <li>options {Object} The parameter to the request call.</li>
11202 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11203 * for the callback function. Defaults to the browser window.</li>
11204 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11205 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11206 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11207 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11208 * params for the post data. Any params will be appended to the URL.</li>
11209 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11211 * @return {Number} transactionId
11213 request : function(o){
11214 if(this.fireEvent("beforerequest", this, o) !== false){
11217 if(typeof p == "function"){
11218 p = p.call(o.scope||window, o);
11220 if(typeof p == "object"){
11221 p = Roo.urlEncode(o.params);
11223 if(this.extraParams){
11224 var extras = Roo.urlEncode(this.extraParams);
11225 p = p ? (p + '&' + extras) : extras;
11228 var url = o.url || this.url;
11229 if(typeof url == 'function'){
11230 url = url.call(o.scope||window, o);
11234 var form = Roo.getDom(o.form);
11235 url = url || form.action;
11237 var enctype = form.getAttribute("enctype");
11238 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11239 return this.doFormUpload(o, p, url);
11241 var f = Roo.lib.Ajax.serializeForm(form);
11242 p = p ? (p + '&' + f) : f;
11245 var hs = o.headers;
11246 if(this.defaultHeaders){
11247 hs = Roo.apply(hs || {}, this.defaultHeaders);
11254 success: this.handleResponse,
11255 failure: this.handleFailure,
11257 argument: {options: o},
11258 timeout : this.timeout
11261 var method = o.method||this.method||(p ? "POST" : "GET");
11263 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11264 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11267 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11271 }else if(this.autoAbort !== false){
11275 if((method == 'GET' && p) || o.xmlData){
11276 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11279 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11280 return this.transId;
11282 Roo.callback(o.callback, o.scope, [o, null, null]);
11288 * Determine whether this object has a request outstanding.
11289 * @param {Number} transactionId (Optional) defaults to the last transaction
11290 * @return {Boolean} True if there is an outstanding request.
11292 isLoading : function(transId){
11294 return Roo.lib.Ajax.isCallInProgress(transId);
11296 return this.transId ? true : false;
11301 * Aborts any outstanding request.
11302 * @param {Number} transactionId (Optional) defaults to the last transaction
11304 abort : function(transId){
11305 if(transId || this.isLoading()){
11306 Roo.lib.Ajax.abort(transId || this.transId);
11311 handleResponse : function(response){
11312 this.transId = false;
11313 var options = response.argument.options;
11314 response.argument = options ? options.argument : null;
11315 this.fireEvent("requestcomplete", this, response, options);
11316 Roo.callback(options.success, options.scope, [response, options]);
11317 Roo.callback(options.callback, options.scope, [options, true, response]);
11321 handleFailure : function(response, e){
11322 this.transId = false;
11323 var options = response.argument.options;
11324 response.argument = options ? options.argument : null;
11325 this.fireEvent("requestexception", this, response, options, e);
11326 Roo.callback(options.failure, options.scope, [response, options]);
11327 Roo.callback(options.callback, options.scope, [options, false, response]);
11331 doFormUpload : function(o, ps, url){
11333 var frame = document.createElement('iframe');
11336 frame.className = 'x-hidden';
11338 frame.src = Roo.SSL_SECURE_URL;
11340 document.body.appendChild(frame);
11343 document.frames[id].name = id;
11346 var form = Roo.getDom(o.form);
11348 form.method = 'POST';
11349 form.enctype = form.encoding = 'multipart/form-data';
11355 if(ps){ // add dynamic params
11357 ps = Roo.urlDecode(ps, false);
11359 if(ps.hasOwnProperty(k)){
11360 hd = document.createElement('input');
11361 hd.type = 'hidden';
11364 form.appendChild(hd);
11371 var r = { // bogus response object
11376 r.argument = o ? o.argument : null;
11381 doc = frame.contentWindow.document;
11383 doc = (frame.contentDocument || window.frames[id].document);
11385 if(doc && doc.body){
11386 r.responseText = doc.body.innerHTML;
11388 if(doc && doc.XMLDocument){
11389 r.responseXML = doc.XMLDocument;
11391 r.responseXML = doc;
11398 Roo.EventManager.removeListener(frame, 'load', cb, this);
11400 this.fireEvent("requestcomplete", this, r, o);
11401 Roo.callback(o.success, o.scope, [r, o]);
11402 Roo.callback(o.callback, o.scope, [o, true, r]);
11404 setTimeout(function(){document.body.removeChild(frame);}, 100);
11407 Roo.EventManager.on(frame, 'load', cb, this);
11410 if(hiddens){ // remove dynamic params
11411 for(var i = 0, len = hiddens.length; i < len; i++){
11412 form.removeChild(hiddens[i]);
11420 * @extends Roo.data.Connection
11421 * Global Ajax request class.
11425 Roo.Ajax = new Roo.data.Connection({
11428 * @cfg {String} url @hide
11431 * @cfg {Object} extraParams @hide
11434 * @cfg {Object} defaultHeaders @hide
11437 * @cfg {String} method (Optional) @hide
11440 * @cfg {Number} timeout (Optional) @hide
11443 * @cfg {Boolean} autoAbort (Optional) @hide
11447 * @cfg {Boolean} disableCaching (Optional) @hide
11451 * @property disableCaching
11452 * True to add a unique cache-buster param to GET requests. (defaults to true)
11457 * The default URL to be used for requests to the server. (defaults to undefined)
11461 * @property extraParams
11462 * An object containing properties which are used as
11463 * extra parameters to each request made by this object. (defaults to undefined)
11467 * @property defaultHeaders
11468 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11473 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11477 * @property timeout
11478 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11483 * @property autoAbort
11484 * Whether a new request should abort any pending requests. (defaults to false)
11490 * Serialize the passed form into a url encoded string
11491 * @param {String/HTMLElement} form
11494 serializeForm : function(form){
11495 return Roo.lib.Ajax.serializeForm(form);
11499 * Ext JS Library 1.1.1
11500 * Copyright(c) 2006-2007, Ext JS, LLC.
11502 * Originally Released Under LGPL - original licence link has changed is not relivant.
11505 * <script type="text/javascript">
11510 * @extends Roo.data.Connection
11511 * Global Ajax request class.
11513 * @instanceOf Roo.data.Connection
11515 Roo.Ajax = new Roo.data.Connection({
11524 * @cfg {String} url @hide
11527 * @cfg {Object} extraParams @hide
11530 * @cfg {Object} defaultHeaders @hide
11533 * @cfg {String} method (Optional) @hide
11536 * @cfg {Number} timeout (Optional) @hide
11539 * @cfg {Boolean} autoAbort (Optional) @hide
11543 * @cfg {Boolean} disableCaching (Optional) @hide
11547 * @property disableCaching
11548 * True to add a unique cache-buster param to GET requests. (defaults to true)
11553 * The default URL to be used for requests to the server. (defaults to undefined)
11557 * @property extraParams
11558 * An object containing properties which are used as
11559 * extra parameters to each request made by this object. (defaults to undefined)
11563 * @property defaultHeaders
11564 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11569 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11573 * @property timeout
11574 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11579 * @property autoAbort
11580 * Whether a new request should abort any pending requests. (defaults to false)
11586 * Serialize the passed form into a url encoded string
11587 * @param {String/HTMLElement} form
11590 serializeForm : function(form){
11591 return Roo.lib.Ajax.serializeForm(form);
11595 * Ext JS Library 1.1.1
11596 * Copyright(c) 2006-2007, Ext JS, LLC.
11598 * Originally Released Under LGPL - original licence link has changed is not relivant.
11601 * <script type="text/javascript">
11606 * @class Roo.UpdateManager
11607 * @extends Roo.util.Observable
11608 * Provides AJAX-style update for Element object.<br><br>
11611 * // Get it from a Roo.Element object
11612 * var el = Roo.get("foo");
11613 * var mgr = el.getUpdateManager();
11614 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11616 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11618 * // or directly (returns the same UpdateManager instance)
11619 * var mgr = new Roo.UpdateManager("myElementId");
11620 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11621 * mgr.on("update", myFcnNeedsToKnow);
11623 // short handed call directly from the element object
11624 Roo.get("foo").load({
11628 text: "Loading Foo..."
11632 * Create new UpdateManager directly.
11633 * @param {String/HTMLElement/Roo.Element} el The element to update
11634 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11636 Roo.UpdateManager = function(el, forceNew){
11638 if(!forceNew && el.updateManager){
11639 return el.updateManager;
11642 * The Element object
11643 * @type Roo.Element
11647 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11650 this.defaultUrl = null;
11654 * @event beforeupdate
11655 * Fired before an update is made, return false from your handler and the update is cancelled.
11656 * @param {Roo.Element} el
11657 * @param {String/Object/Function} url
11658 * @param {String/Object} params
11660 "beforeupdate": true,
11663 * Fired after successful update is made.
11664 * @param {Roo.Element} el
11665 * @param {Object} oResponseObject The response Object
11670 * Fired on update failure.
11671 * @param {Roo.Element} el
11672 * @param {Object} oResponseObject The response Object
11676 var d = Roo.UpdateManager.defaults;
11678 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11681 this.sslBlankUrl = d.sslBlankUrl;
11683 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11686 this.disableCaching = d.disableCaching;
11688 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11691 this.indicatorText = d.indicatorText;
11693 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11696 this.showLoadIndicator = d.showLoadIndicator;
11698 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11701 this.timeout = d.timeout;
11704 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11707 this.loadScripts = d.loadScripts;
11710 * Transaction object of current executing transaction
11712 this.transaction = null;
11717 this.autoRefreshProcId = null;
11719 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11722 this.refreshDelegate = this.refresh.createDelegate(this);
11724 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11727 this.updateDelegate = this.update.createDelegate(this);
11729 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11732 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11736 this.successDelegate = this.processSuccess.createDelegate(this);
11740 this.failureDelegate = this.processFailure.createDelegate(this);
11742 if(!this.renderer){
11744 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11746 this.renderer = new Roo.UpdateManager.BasicRenderer();
11749 Roo.UpdateManager.superclass.constructor.call(this);
11752 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11754 * Get the Element this UpdateManager is bound to
11755 * @return {Roo.Element} The element
11757 getEl : function(){
11761 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11762 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11765 url: "your-url.php",<br/>
11766 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11767 callback: yourFunction,<br/>
11768 scope: yourObject, //(optional scope) <br/>
11769 discardUrl: false, <br/>
11770 nocache: false,<br/>
11771 text: "Loading...",<br/>
11773 scripts: false<br/>
11776 * The only required property is url. The optional properties nocache, text and scripts
11777 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11778 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11779 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11780 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11782 update : function(url, params, callback, discardUrl){
11783 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11784 var method = this.method, cfg;
11785 if(typeof url == "object"){ // must be config object
11788 params = params || cfg.params;
11789 callback = callback || cfg.callback;
11790 discardUrl = discardUrl || cfg.discardUrl;
11791 if(callback && cfg.scope){
11792 callback = callback.createDelegate(cfg.scope);
11794 if(typeof cfg.method != "undefined"){method = cfg.method;};
11795 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11796 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11797 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11798 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11800 this.showLoading();
11802 this.defaultUrl = url;
11804 if(typeof url == "function"){
11805 url = url.call(this);
11808 method = method || (params ? "POST" : "GET");
11809 if(method == "GET"){
11810 url = this.prepareUrl(url);
11813 var o = Roo.apply(cfg ||{}, {
11816 success: this.successDelegate,
11817 failure: this.failureDelegate,
11818 callback: undefined,
11819 timeout: (this.timeout*1000),
11820 argument: {"url": url, "form": null, "callback": callback, "params": params}
11823 this.transaction = Roo.Ajax.request(o);
11828 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11829 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11830 * @param {String/HTMLElement} form The form Id or form element
11831 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11832 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11833 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11835 formUpdate : function(form, url, reset, callback){
11836 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11837 if(typeof url == "function"){
11838 url = url.call(this);
11840 form = Roo.getDom(form);
11841 this.transaction = Roo.Ajax.request({
11844 success: this.successDelegate,
11845 failure: this.failureDelegate,
11846 timeout: (this.timeout*1000),
11847 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11849 this.showLoading.defer(1, this);
11854 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11855 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11857 refresh : function(callback){
11858 if(this.defaultUrl == null){
11861 this.update(this.defaultUrl, null, callback, true);
11865 * Set this element to auto refresh.
11866 * @param {Number} interval How often to update (in seconds).
11867 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11868 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11869 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11870 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11872 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11874 this.update(url || this.defaultUrl, params, callback, true);
11876 if(this.autoRefreshProcId){
11877 clearInterval(this.autoRefreshProcId);
11879 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11883 * Stop auto refresh on this element.
11885 stopAutoRefresh : function(){
11886 if(this.autoRefreshProcId){
11887 clearInterval(this.autoRefreshProcId);
11888 delete this.autoRefreshProcId;
11892 isAutoRefreshing : function(){
11893 return this.autoRefreshProcId ? true : false;
11896 * Called to update the element to "Loading" state. Override to perform custom action.
11898 showLoading : function(){
11899 if(this.showLoadIndicator){
11900 this.el.update(this.indicatorText);
11905 * Adds unique parameter to query string if disableCaching = true
11908 prepareUrl : function(url){
11909 if(this.disableCaching){
11910 var append = "_dc=" + (new Date().getTime());
11911 if(url.indexOf("?") !== -1){
11912 url += "&" + append;
11914 url += "?" + append;
11923 processSuccess : function(response){
11924 this.transaction = null;
11925 if(response.argument.form && response.argument.reset){
11926 try{ // put in try/catch since some older FF releases had problems with this
11927 response.argument.form.reset();
11930 if(this.loadScripts){
11931 this.renderer.render(this.el, response, this,
11932 this.updateComplete.createDelegate(this, [response]));
11934 this.renderer.render(this.el, response, this);
11935 this.updateComplete(response);
11939 updateComplete : function(response){
11940 this.fireEvent("update", this.el, response);
11941 if(typeof response.argument.callback == "function"){
11942 response.argument.callback(this.el, true, response);
11949 processFailure : function(response){
11950 this.transaction = null;
11951 this.fireEvent("failure", this.el, response);
11952 if(typeof response.argument.callback == "function"){
11953 response.argument.callback(this.el, false, response);
11958 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11959 * @param {Object} renderer The object implementing the render() method
11961 setRenderer : function(renderer){
11962 this.renderer = renderer;
11965 getRenderer : function(){
11966 return this.renderer;
11970 * Set the defaultUrl used for updates
11971 * @param {String/Function} defaultUrl The url or a function to call to get the url
11973 setDefaultUrl : function(defaultUrl){
11974 this.defaultUrl = defaultUrl;
11978 * Aborts the executing transaction
11980 abort : function(){
11981 if(this.transaction){
11982 Roo.Ajax.abort(this.transaction);
11987 * Returns true if an update is in progress
11988 * @return {Boolean}
11990 isUpdating : function(){
11991 if(this.transaction){
11992 return Roo.Ajax.isLoading(this.transaction);
11999 * @class Roo.UpdateManager.defaults
12000 * @static (not really - but it helps the doc tool)
12001 * The defaults collection enables customizing the default properties of UpdateManager
12003 Roo.UpdateManager.defaults = {
12005 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12011 * True to process scripts by default (Defaults to false).
12014 loadScripts : false,
12017 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12020 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12022 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12025 disableCaching : false,
12027 * Whether to show indicatorText when loading (Defaults to true).
12030 showLoadIndicator : true,
12032 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12035 indicatorText : '<div class="loading-indicator">Loading...</div>'
12039 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12041 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12042 * @param {String/HTMLElement/Roo.Element} el The element to update
12043 * @param {String} url The url
12044 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12045 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12048 * @member Roo.UpdateManager
12050 Roo.UpdateManager.updateElement = function(el, url, params, options){
12051 var um = Roo.get(el, true).getUpdateManager();
12052 Roo.apply(um, options);
12053 um.update(url, params, options ? options.callback : null);
12055 // alias for backwards compat
12056 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12058 * @class Roo.UpdateManager.BasicRenderer
12059 * Default Content renderer. Updates the elements innerHTML with the responseText.
12061 Roo.UpdateManager.BasicRenderer = function(){};
12063 Roo.UpdateManager.BasicRenderer.prototype = {
12065 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12066 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12067 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12068 * @param {Roo.Element} el The element being rendered
12069 * @param {Object} response The YUI Connect response object
12070 * @param {UpdateManager} updateManager The calling update manager
12071 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12073 render : function(el, response, updateManager, callback){
12074 el.update(response.responseText, updateManager.loadScripts, callback);
12079 * Ext JS Library 1.1.1
12080 * Copyright(c) 2006-2007, Ext JS, LLC.
12082 * Originally Released Under LGPL - original licence link has changed is not relivant.
12085 * <script type="text/javascript">
12089 * @class Roo.util.DelayedTask
12090 * Provides a convenient method of performing setTimeout where a new
12091 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12092 * You can use this class to buffer
12093 * the keypress events for a certain number of milliseconds, and perform only if they stop
12094 * for that amount of time.
12095 * @constructor The parameters to this constructor serve as defaults and are not required.
12096 * @param {Function} fn (optional) The default function to timeout
12097 * @param {Object} scope (optional) The default scope of that timeout
12098 * @param {Array} args (optional) The default Array of arguments
12100 Roo.util.DelayedTask = function(fn, scope, args){
12101 var id = null, d, t;
12103 var call = function(){
12104 var now = new Date().getTime();
12108 fn.apply(scope, args || []);
12112 * Cancels any pending timeout and queues a new one
12113 * @param {Number} delay The milliseconds to delay
12114 * @param {Function} newFn (optional) Overrides function passed to constructor
12115 * @param {Object} newScope (optional) Overrides scope passed to constructor
12116 * @param {Array} newArgs (optional) Overrides args passed to constructor
12118 this.delay = function(delay, newFn, newScope, newArgs){
12119 if(id && delay != d){
12123 t = new Date().getTime();
12125 scope = newScope || scope;
12126 args = newArgs || args;
12128 id = setInterval(call, d);
12133 * Cancel the last queued timeout
12135 this.cancel = function(){
12143 * Ext JS Library 1.1.1
12144 * Copyright(c) 2006-2007, Ext JS, LLC.
12146 * Originally Released Under LGPL - original licence link has changed is not relivant.
12149 * <script type="text/javascript">
12153 Roo.util.TaskRunner = function(interval){
12154 interval = interval || 10;
12155 var tasks = [], removeQueue = [];
12157 var running = false;
12159 var stopThread = function(){
12165 var startThread = function(){
12168 id = setInterval(runTasks, interval);
12172 var removeTask = function(task){
12173 removeQueue.push(task);
12179 var runTasks = function(){
12180 if(removeQueue.length > 0){
12181 for(var i = 0, len = removeQueue.length; i < len; i++){
12182 tasks.remove(removeQueue[i]);
12185 if(tasks.length < 1){
12190 var now = new Date().getTime();
12191 for(var i = 0, len = tasks.length; i < len; ++i){
12193 var itime = now - t.taskRunTime;
12194 if(t.interval <= itime){
12195 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12196 t.taskRunTime = now;
12197 if(rt === false || t.taskRunCount === t.repeat){
12202 if(t.duration && t.duration <= (now - t.taskStartTime)){
12209 * Queues a new task.
12210 * @param {Object} task
12212 this.start = function(task){
12214 task.taskStartTime = new Date().getTime();
12215 task.taskRunTime = 0;
12216 task.taskRunCount = 0;
12221 this.stop = function(task){
12226 this.stopAll = function(){
12228 for(var i = 0, len = tasks.length; i < len; i++){
12229 if(tasks[i].onStop){
12238 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12240 * Ext JS Library 1.1.1
12241 * Copyright(c) 2006-2007, Ext JS, LLC.
12243 * Originally Released Under LGPL - original licence link has changed is not relivant.
12246 * <script type="text/javascript">
12251 * @class Roo.util.MixedCollection
12252 * @extends Roo.util.Observable
12253 * A Collection class that maintains both numeric indexes and keys and exposes events.
12255 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12256 * collection (defaults to false)
12257 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12258 * and return the key value for that item. This is used when available to look up the key on items that
12259 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12260 * equivalent to providing an implementation for the {@link #getKey} method.
12262 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12270 * Fires when the collection is cleared.
12275 * Fires when an item is added to the collection.
12276 * @param {Number} index The index at which the item was added.
12277 * @param {Object} o The item added.
12278 * @param {String} key The key associated with the added item.
12283 * Fires when an item is replaced in the collection.
12284 * @param {String} key he key associated with the new added.
12285 * @param {Object} old The item being replaced.
12286 * @param {Object} new The new item.
12291 * Fires when an item is removed from the collection.
12292 * @param {Object} o The item being removed.
12293 * @param {String} key (optional) The key associated with the removed item.
12298 this.allowFunctions = allowFunctions === true;
12300 this.getKey = keyFn;
12302 Roo.util.MixedCollection.superclass.constructor.call(this);
12305 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12306 allowFunctions : false,
12309 * Adds an item to the collection.
12310 * @param {String} key The key to associate with the item
12311 * @param {Object} o The item to add.
12312 * @return {Object} The item added.
12314 add : function(key, o){
12315 if(arguments.length == 1){
12317 key = this.getKey(o);
12319 if(typeof key == "undefined" || key === null){
12321 this.items.push(o);
12322 this.keys.push(null);
12324 var old = this.map[key];
12326 return this.replace(key, o);
12329 this.items.push(o);
12331 this.keys.push(key);
12333 this.fireEvent("add", this.length-1, o, key);
12338 * MixedCollection has a generic way to fetch keys if you implement getKey.
12341 var mc = new Roo.util.MixedCollection();
12342 mc.add(someEl.dom.id, someEl);
12343 mc.add(otherEl.dom.id, otherEl);
12347 var mc = new Roo.util.MixedCollection();
12348 mc.getKey = function(el){
12354 // or via the constructor
12355 var mc = new Roo.util.MixedCollection(false, function(el){
12361 * @param o {Object} The item for which to find the key.
12362 * @return {Object} The key for the passed item.
12364 getKey : function(o){
12369 * Replaces an item in the collection.
12370 * @param {String} key The key associated with the item to replace, or the item to replace.
12371 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12372 * @return {Object} The new item.
12374 replace : function(key, o){
12375 if(arguments.length == 1){
12377 key = this.getKey(o);
12379 var old = this.item(key);
12380 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12381 return this.add(key, o);
12383 var index = this.indexOfKey(key);
12384 this.items[index] = o;
12386 this.fireEvent("replace", key, old, o);
12391 * Adds all elements of an Array or an Object to the collection.
12392 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12393 * an Array of values, each of which are added to the collection.
12395 addAll : function(objs){
12396 if(arguments.length > 1 || objs instanceof Array){
12397 var args = arguments.length > 1 ? arguments : objs;
12398 for(var i = 0, len = args.length; i < len; i++){
12402 for(var key in objs){
12403 if(this.allowFunctions || typeof objs[key] != "function"){
12404 this.add(key, objs[key]);
12411 * Executes the specified function once for every item in the collection, passing each
12412 * item as the first and only parameter. returning false from the function will stop the iteration.
12413 * @param {Function} fn The function to execute for each item.
12414 * @param {Object} scope (optional) The scope in which to execute the function.
12416 each : function(fn, scope){
12417 var items = [].concat(this.items); // each safe for removal
12418 for(var i = 0, len = items.length; i < len; i++){
12419 if(fn.call(scope || items[i], items[i], i, len) === false){
12426 * Executes the specified function once for every key in the collection, passing each
12427 * key, and its associated item as the first two parameters.
12428 * @param {Function} fn The function to execute for each item.
12429 * @param {Object} scope (optional) The scope in which to execute the function.
12431 eachKey : function(fn, scope){
12432 for(var i = 0, len = this.keys.length; i < len; i++){
12433 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12438 * Returns the first item in the collection which elicits a true return value from the
12439 * passed selection function.
12440 * @param {Function} fn The selection function to execute for each item.
12441 * @param {Object} scope (optional) The scope in which to execute the function.
12442 * @return {Object} The first item in the collection which returned true from the selection function.
12444 find : function(fn, scope){
12445 for(var i = 0, len = this.items.length; i < len; i++){
12446 if(fn.call(scope || window, this.items[i], this.keys[i])){
12447 return this.items[i];
12454 * Inserts an item at the specified index in the collection.
12455 * @param {Number} index The index to insert the item at.
12456 * @param {String} key The key to associate with the new item, or the item itself.
12457 * @param {Object} o (optional) If the second parameter was a key, the new item.
12458 * @return {Object} The item inserted.
12460 insert : function(index, key, o){
12461 if(arguments.length == 2){
12463 key = this.getKey(o);
12465 if(index >= this.length){
12466 return this.add(key, o);
12469 this.items.splice(index, 0, o);
12470 if(typeof key != "undefined" && key != null){
12473 this.keys.splice(index, 0, key);
12474 this.fireEvent("add", index, o, key);
12479 * Removed an item from the collection.
12480 * @param {Object} o The item to remove.
12481 * @return {Object} The item removed.
12483 remove : function(o){
12484 return this.removeAt(this.indexOf(o));
12488 * Remove an item from a specified index in the collection.
12489 * @param {Number} index The index within the collection of the item to remove.
12491 removeAt : function(index){
12492 if(index < this.length && index >= 0){
12494 var o = this.items[index];
12495 this.items.splice(index, 1);
12496 var key = this.keys[index];
12497 if(typeof key != "undefined"){
12498 delete this.map[key];
12500 this.keys.splice(index, 1);
12501 this.fireEvent("remove", o, key);
12506 * Removed an item associated with the passed key fom the collection.
12507 * @param {String} key The key of the item to remove.
12509 removeKey : function(key){
12510 return this.removeAt(this.indexOfKey(key));
12514 * Returns the number of items in the collection.
12515 * @return {Number} the number of items in the collection.
12517 getCount : function(){
12518 return this.length;
12522 * Returns index within the collection of the passed Object.
12523 * @param {Object} o The item to find the index of.
12524 * @return {Number} index of the item.
12526 indexOf : function(o){
12527 if(!this.items.indexOf){
12528 for(var i = 0, len = this.items.length; i < len; i++){
12529 if(this.items[i] == o) return i;
12533 return this.items.indexOf(o);
12538 * Returns index within the collection of the passed key.
12539 * @param {String} key The key to find the index of.
12540 * @return {Number} index of the key.
12542 indexOfKey : function(key){
12543 if(!this.keys.indexOf){
12544 for(var i = 0, len = this.keys.length; i < len; i++){
12545 if(this.keys[i] == key) return i;
12549 return this.keys.indexOf(key);
12554 * Returns the item associated with the passed key OR index. Key has priority over index.
12555 * @param {String/Number} key The key or index of the item.
12556 * @return {Object} The item associated with the passed key.
12558 item : function(key){
12559 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12560 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12564 * Returns the item at the specified index.
12565 * @param {Number} index The index of the item.
12568 itemAt : function(index){
12569 return this.items[index];
12573 * Returns the item associated with the passed key.
12574 * @param {String/Number} key The key of the item.
12575 * @return {Object} The item associated with the passed key.
12577 key : function(key){
12578 return this.map[key];
12582 * Returns true if the collection contains the passed Object as an item.
12583 * @param {Object} o The Object to look for in the collection.
12584 * @return {Boolean} True if the collection contains the Object as an item.
12586 contains : function(o){
12587 return this.indexOf(o) != -1;
12591 * Returns true if the collection contains the passed Object as a key.
12592 * @param {String} key The key to look for in the collection.
12593 * @return {Boolean} True if the collection contains the Object as a key.
12595 containsKey : function(key){
12596 return typeof this.map[key] != "undefined";
12600 * Removes all items from the collection.
12602 clear : function(){
12607 this.fireEvent("clear");
12611 * Returns the first item in the collection.
12612 * @return {Object} the first item in the collection..
12614 first : function(){
12615 return this.items[0];
12619 * Returns the last item in the collection.
12620 * @return {Object} the last item in the collection..
12623 return this.items[this.length-1];
12626 _sort : function(property, dir, fn){
12627 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12628 fn = fn || function(a, b){
12631 var c = [], k = this.keys, items = this.items;
12632 for(var i = 0, len = items.length; i < len; i++){
12633 c[c.length] = {key: k[i], value: items[i], index: i};
12635 c.sort(function(a, b){
12636 var v = fn(a[property], b[property]) * dsc;
12638 v = (a.index < b.index ? -1 : 1);
12642 for(var i = 0, len = c.length; i < len; i++){
12643 items[i] = c[i].value;
12646 this.fireEvent("sort", this);
12650 * Sorts this collection with the passed comparison function
12651 * @param {String} direction (optional) "ASC" or "DESC"
12652 * @param {Function} fn (optional) comparison function
12654 sort : function(dir, fn){
12655 this._sort("value", dir, fn);
12659 * Sorts this collection by keys
12660 * @param {String} direction (optional) "ASC" or "DESC"
12661 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12663 keySort : function(dir, fn){
12664 this._sort("key", dir, fn || function(a, b){
12665 return String(a).toUpperCase()-String(b).toUpperCase();
12670 * Returns a range of items in this collection
12671 * @param {Number} startIndex (optional) defaults to 0
12672 * @param {Number} endIndex (optional) default to the last item
12673 * @return {Array} An array of items
12675 getRange : function(start, end){
12676 var items = this.items;
12677 if(items.length < 1){
12680 start = start || 0;
12681 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12684 for(var i = start; i <= end; i++) {
12685 r[r.length] = items[i];
12688 for(var i = start; i >= end; i--) {
12689 r[r.length] = items[i];
12696 * Filter the <i>objects</i> in this collection by a specific property.
12697 * Returns a new collection that has been filtered.
12698 * @param {String} property A property on your objects
12699 * @param {String/RegExp} value Either string that the property values
12700 * should start with or a RegExp to test against the property
12701 * @return {MixedCollection} The new filtered collection
12703 filter : function(property, value){
12704 if(!value.exec){ // not a regex
12705 value = String(value);
12706 if(value.length == 0){
12707 return this.clone();
12709 value = new RegExp("^" + Roo.escapeRe(value), "i");
12711 return this.filterBy(function(o){
12712 return o && value.test(o[property]);
12717 * Filter by a function. * Returns a new collection that has been filtered.
12718 * The passed function will be called with each
12719 * object in the collection. If the function returns true, the value is included
12720 * otherwise it is filtered.
12721 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12722 * @param {Object} scope (optional) The scope of the function (defaults to this)
12723 * @return {MixedCollection} The new filtered collection
12725 filterBy : function(fn, scope){
12726 var r = new Roo.util.MixedCollection();
12727 r.getKey = this.getKey;
12728 var k = this.keys, it = this.items;
12729 for(var i = 0, len = it.length; i < len; i++){
12730 if(fn.call(scope||this, it[i], k[i])){
12731 r.add(k[i], it[i]);
12738 * Creates a duplicate of this collection
12739 * @return {MixedCollection}
12741 clone : function(){
12742 var r = new Roo.util.MixedCollection();
12743 var k = this.keys, it = this.items;
12744 for(var i = 0, len = it.length; i < len; i++){
12745 r.add(k[i], it[i]);
12747 r.getKey = this.getKey;
12752 * Returns the item associated with the passed key or index.
12754 * @param {String/Number} key The key or index of the item.
12755 * @return {Object} The item associated with the passed key.
12757 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12759 * Ext JS Library 1.1.1
12760 * Copyright(c) 2006-2007, Ext JS, LLC.
12762 * Originally Released Under LGPL - original licence link has changed is not relivant.
12765 * <script type="text/javascript">
12768 * @class Roo.util.JSON
12769 * Modified version of Douglas Crockford"s json.js that doesn"t
12770 * mess with the Object prototype
12771 * http://www.json.org/js.html
12774 Roo.util.JSON = new (function(){
12775 var useHasOwn = {}.hasOwnProperty ? true : false;
12777 // crashes Safari in some instances
12778 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12780 var pad = function(n) {
12781 return n < 10 ? "0" + n : n;
12794 var encodeString = function(s){
12795 if (/["\\\x00-\x1f]/.test(s)) {
12796 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12801 c = b.charCodeAt();
12803 Math.floor(c / 16).toString(16) +
12804 (c % 16).toString(16);
12807 return '"' + s + '"';
12810 var encodeArray = function(o){
12811 var a = ["["], b, i, l = o.length, v;
12812 for (i = 0; i < l; i += 1) {
12814 switch (typeof v) {
12823 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12831 var encodeDate = function(o){
12832 return '"' + o.getFullYear() + "-" +
12833 pad(o.getMonth() + 1) + "-" +
12834 pad(o.getDate()) + "T" +
12835 pad(o.getHours()) + ":" +
12836 pad(o.getMinutes()) + ":" +
12837 pad(o.getSeconds()) + '"';
12841 * Encodes an Object, Array or other value
12842 * @param {Mixed} o The variable to encode
12843 * @return {String} The JSON string
12845 this.encode = function(o)
12847 // should this be extended to fully wrap stringify..
12849 if(typeof o == "undefined" || o === null){
12851 }else if(o instanceof Array){
12852 return encodeArray(o);
12853 }else if(o instanceof Date){
12854 return encodeDate(o);
12855 }else if(typeof o == "string"){
12856 return encodeString(o);
12857 }else if(typeof o == "number"){
12858 return isFinite(o) ? String(o) : "null";
12859 }else if(typeof o == "boolean"){
12862 var a = ["{"], b, i, v;
12864 if(!useHasOwn || o.hasOwnProperty(i)) {
12866 switch (typeof v) {
12875 a.push(this.encode(i), ":",
12876 v === null ? "null" : this.encode(v));
12887 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12888 * @param {String} json The JSON string
12889 * @return {Object} The resulting object
12891 this.decode = function(json){
12893 return /** eval:var:json */ eval("(" + json + ')');
12897 * Shorthand for {@link Roo.util.JSON#encode}
12898 * @member Roo encode
12900 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12902 * Shorthand for {@link Roo.util.JSON#decode}
12903 * @member Roo decode
12905 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12908 * Ext JS Library 1.1.1
12909 * Copyright(c) 2006-2007, Ext JS, LLC.
12911 * Originally Released Under LGPL - original licence link has changed is not relivant.
12914 * <script type="text/javascript">
12918 * @class Roo.util.Format
12919 * Reusable data formatting functions
12922 Roo.util.Format = function(){
12923 var trimRe = /^\s+|\s+$/g;
12926 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12927 * @param {String} value The string to truncate
12928 * @param {Number} length The maximum length to allow before truncating
12929 * @return {String} The converted text
12931 ellipsis : function(value, len){
12932 if(value && value.length > len){
12933 return value.substr(0, len-3)+"...";
12939 * Checks a reference and converts it to empty string if it is undefined
12940 * @param {Mixed} value Reference to check
12941 * @return {Mixed} Empty string if converted, otherwise the original value
12943 undef : function(value){
12944 return typeof value != "undefined" ? value : "";
12948 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12949 * @param {String} value The string to encode
12950 * @return {String} The encoded text
12952 htmlEncode : function(value){
12953 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12957 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12958 * @param {String} value The string to decode
12959 * @return {String} The decoded text
12961 htmlDecode : function(value){
12962 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12966 * Trims any whitespace from either side of a string
12967 * @param {String} value The text to trim
12968 * @return {String} The trimmed text
12970 trim : function(value){
12971 return String(value).replace(trimRe, "");
12975 * Returns a substring from within an original string
12976 * @param {String} value The original text
12977 * @param {Number} start The start index of the substring
12978 * @param {Number} length The length of the substring
12979 * @return {String} The substring
12981 substr : function(value, start, length){
12982 return String(value).substr(start, length);
12986 * Converts a string to all lower case letters
12987 * @param {String} value The text to convert
12988 * @return {String} The converted text
12990 lowercase : function(value){
12991 return String(value).toLowerCase();
12995 * Converts a string to all upper case letters
12996 * @param {String} value The text to convert
12997 * @return {String} The converted text
12999 uppercase : function(value){
13000 return String(value).toUpperCase();
13004 * Converts the first character only of a string to upper case
13005 * @param {String} value The text to convert
13006 * @return {String} The converted text
13008 capitalize : function(value){
13009 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13013 call : function(value, fn){
13014 if(arguments.length > 2){
13015 var args = Array.prototype.slice.call(arguments, 2);
13016 args.unshift(value);
13018 return /** eval:var:value */ eval(fn).apply(window, args);
13020 /** eval:var:value */
13021 return /** eval:var:value */ eval(fn).call(window, value);
13027 * safer version of Math.toFixed..??/
13028 * @param {Number/String} value The numeric value to format
13029 * @param {Number/String} value Decimal places
13030 * @return {String} The formatted currency string
13032 toFixed : function(v, n)
13034 // why not use to fixed - precision is buggered???
13036 return Math.round(v-0);
13038 var fact = Math.pow(10,n+1);
13039 v = (Math.round((v-0)*fact))/fact;
13040 var z = (''+fact).substring(2);
13041 if (v == Math.floor(v)) {
13042 return Math.floor(v) + '.' + z;
13045 // now just padd decimals..
13046 var ps = String(v).split('.');
13047 var fd = (ps[1] + z);
13048 var r = fd.substring(0,n);
13049 var rm = fd.substring(n);
13051 return ps[0] + '.' + r;
13053 r*=1; // turn it into a number;
13055 if (String(r).length != n) {
13058 r = String(r).substring(1); // chop the end off.
13061 return ps[0] + '.' + r;
13066 * Format a number as US currency
13067 * @param {Number/String} value The numeric value to format
13068 * @return {String} The formatted currency string
13070 usMoney : function(v){
13071 v = (Math.round((v-0)*100))/100;
13072 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13074 var ps = v.split('.');
13076 var sub = ps[1] ? '.'+ ps[1] : '.00';
13077 var r = /(\d+)(\d{3})/;
13078 while (r.test(whole)) {
13079 whole = whole.replace(r, '$1' + ',' + '$2');
13081 return "$" + whole + sub ;
13085 * Parse a value into a formatted date using the specified format pattern.
13086 * @param {Mixed} value The value to format
13087 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13088 * @return {String} The formatted date string
13090 date : function(v, format){
13094 if(!(v instanceof Date)){
13095 v = new Date(Date.parse(v));
13097 return v.dateFormat(format || "m/d/Y");
13101 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13102 * @param {String} format Any valid date format string
13103 * @return {Function} The date formatting function
13105 dateRenderer : function(format){
13106 return function(v){
13107 return Roo.util.Format.date(v, format);
13112 stripTagsRE : /<\/?[^>]+>/gi,
13115 * Strips all HTML tags
13116 * @param {Mixed} value The text from which to strip tags
13117 * @return {String} The stripped text
13119 stripTags : function(v){
13120 return !v ? v : String(v).replace(this.stripTagsRE, "");
13125 * Ext JS Library 1.1.1
13126 * Copyright(c) 2006-2007, Ext JS, LLC.
13128 * Originally Released Under LGPL - original licence link has changed is not relivant.
13131 * <script type="text/javascript">
13138 * @class Roo.MasterTemplate
13139 * @extends Roo.Template
13140 * Provides a template that can have child templates. The syntax is:
13142 var t = new Roo.MasterTemplate(
13143 '<select name="{name}">',
13144 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13147 t.add('options', {value: 'foo', text: 'bar'});
13148 // or you can add multiple child elements in one shot
13149 t.addAll('options', [
13150 {value: 'foo', text: 'bar'},
13151 {value: 'foo2', text: 'bar2'},
13152 {value: 'foo3', text: 'bar3'}
13154 // then append, applying the master template values
13155 t.append('my-form', {name: 'my-select'});
13157 * A name attribute for the child template is not required if you have only one child
13158 * template or you want to refer to them by index.
13160 Roo.MasterTemplate = function(){
13161 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13162 this.originalHtml = this.html;
13164 var m, re = this.subTemplateRe;
13167 while(m = re.exec(this.html)){
13168 var name = m[1], content = m[2];
13173 tpl : new Roo.Template(content)
13176 st[name] = st[subIndex];
13178 st[subIndex].tpl.compile();
13179 st[subIndex].tpl.call = this.call.createDelegate(this);
13182 this.subCount = subIndex;
13185 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13187 * The regular expression used to match sub templates
13191 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13194 * Applies the passed values to a child template.
13195 * @param {String/Number} name (optional) The name or index of the child template
13196 * @param {Array/Object} values The values to be applied to the template
13197 * @return {MasterTemplate} this
13199 add : function(name, values){
13200 if(arguments.length == 1){
13201 values = arguments[0];
13204 var s = this.subs[name];
13205 s.buffer[s.buffer.length] = s.tpl.apply(values);
13210 * Applies all the passed values to a child template.
13211 * @param {String/Number} name (optional) The name or index of the child template
13212 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13213 * @param {Boolean} reset (optional) True to reset the template first
13214 * @return {MasterTemplate} this
13216 fill : function(name, values, reset){
13218 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13226 for(var i = 0, len = values.length; i < len; i++){
13227 this.add(name, values[i]);
13233 * Resets the template for reuse
13234 * @return {MasterTemplate} this
13236 reset : function(){
13238 for(var i = 0; i < this.subCount; i++){
13244 applyTemplate : function(values){
13246 var replaceIndex = -1;
13247 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13248 return s[++replaceIndex].buffer.join("");
13250 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13253 apply : function(){
13254 return this.applyTemplate.apply(this, arguments);
13257 compile : function(){return this;}
13261 * Alias for fill().
13264 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13266 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13267 * var tpl = Roo.MasterTemplate.from('element-id');
13268 * @param {String/HTMLElement} el
13269 * @param {Object} config
13272 Roo.MasterTemplate.from = function(el, config){
13273 el = Roo.getDom(el);
13274 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13277 * Ext JS Library 1.1.1
13278 * Copyright(c) 2006-2007, Ext JS, LLC.
13280 * Originally Released Under LGPL - original licence link has changed is not relivant.
13283 * <script type="text/javascript">
13288 * @class Roo.util.CSS
13289 * Utility class for manipulating CSS rules
13292 Roo.util.CSS = function(){
13294 var doc = document;
13296 var camelRe = /(-[a-z])/gi;
13297 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13301 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13302 * tag and appended to the HEAD of the document.
13303 * @param {String|Object} cssText The text containing the css rules
13304 * @param {String} id An id to add to the stylesheet for later removal
13305 * @return {StyleSheet}
13307 createStyleSheet : function(cssText, id){
13309 var head = doc.getElementsByTagName("head")[0];
13310 var nrules = doc.createElement("style");
13311 nrules.setAttribute("type", "text/css");
13313 nrules.setAttribute("id", id);
13315 if (typeof(cssText) != 'string') {
13316 // support object maps..
13317 // not sure if this a good idea..
13318 // perhaps it should be merged with the general css handling
13319 // and handle js style props.
13320 var cssTextNew = [];
13321 for(var n in cssText) {
13323 for(var k in cssText[n]) {
13324 citems.push( k + ' : ' +cssText[n][k] + ';' );
13326 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13329 cssText = cssTextNew.join("\n");
13335 head.appendChild(nrules);
13336 ss = nrules.styleSheet;
13337 ss.cssText = cssText;
13340 nrules.appendChild(doc.createTextNode(cssText));
13342 nrules.cssText = cssText;
13344 head.appendChild(nrules);
13345 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13347 this.cacheStyleSheet(ss);
13352 * Removes a style or link tag by id
13353 * @param {String} id The id of the tag
13355 removeStyleSheet : function(id){
13356 var existing = doc.getElementById(id);
13358 existing.parentNode.removeChild(existing);
13363 * Dynamically swaps an existing stylesheet reference for a new one
13364 * @param {String} id The id of an existing link tag to remove
13365 * @param {String} url The href of the new stylesheet to include
13367 swapStyleSheet : function(id, url){
13368 this.removeStyleSheet(id);
13369 var ss = doc.createElement("link");
13370 ss.setAttribute("rel", "stylesheet");
13371 ss.setAttribute("type", "text/css");
13372 ss.setAttribute("id", id);
13373 ss.setAttribute("href", url);
13374 doc.getElementsByTagName("head")[0].appendChild(ss);
13378 * Refresh the rule cache if you have dynamically added stylesheets
13379 * @return {Object} An object (hash) of rules indexed by selector
13381 refreshCache : function(){
13382 return this.getRules(true);
13386 cacheStyleSheet : function(stylesheet){
13390 try{// try catch for cross domain access issue
13391 var ssRules = stylesheet.cssRules || stylesheet.rules;
13392 for(var j = ssRules.length-1; j >= 0; --j){
13393 rules[ssRules[j].selectorText] = ssRules[j];
13399 * Gets all css rules for the document
13400 * @param {Boolean} refreshCache true to refresh the internal cache
13401 * @return {Object} An object (hash) of rules indexed by selector
13403 getRules : function(refreshCache){
13404 if(rules == null || refreshCache){
13406 var ds = doc.styleSheets;
13407 for(var i =0, len = ds.length; i < len; i++){
13409 this.cacheStyleSheet(ds[i]);
13417 * Gets an an individual CSS rule by selector(s)
13418 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13419 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13420 * @return {CSSRule} The CSS rule or null if one is not found
13422 getRule : function(selector, refreshCache){
13423 var rs = this.getRules(refreshCache);
13424 if(!(selector instanceof Array)){
13425 return rs[selector];
13427 for(var i = 0; i < selector.length; i++){
13428 if(rs[selector[i]]){
13429 return rs[selector[i]];
13437 * Updates a rule property
13438 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13439 * @param {String} property The css property
13440 * @param {String} value The new value for the property
13441 * @return {Boolean} true If a rule was found and updated
13443 updateRule : function(selector, property, value){
13444 if(!(selector instanceof Array)){
13445 var rule = this.getRule(selector);
13447 rule.style[property.replace(camelRe, camelFn)] = value;
13451 for(var i = 0; i < selector.length; i++){
13452 if(this.updateRule(selector[i], property, value)){
13462 * Ext JS Library 1.1.1
13463 * Copyright(c) 2006-2007, Ext JS, LLC.
13465 * Originally Released Under LGPL - original licence link has changed is not relivant.
13468 * <script type="text/javascript">
13474 * @class Roo.util.ClickRepeater
13475 * @extends Roo.util.Observable
13477 * A wrapper class which can be applied to any element. Fires a "click" event while the
13478 * mouse is pressed. The interval between firings may be specified in the config but
13479 * defaults to 10 milliseconds.
13481 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13483 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13484 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13485 * Similar to an autorepeat key delay.
13486 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13487 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13488 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13489 * "interval" and "delay" are ignored. "immediate" is honored.
13490 * @cfg {Boolean} preventDefault True to prevent the default click event
13491 * @cfg {Boolean} stopDefault True to stop the default click event
13494 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13495 * 2007-02-02 jvs Renamed to ClickRepeater
13496 * 2007-02-03 jvs Modifications for FF Mac and Safari
13499 * @param {String/HTMLElement/Element} el The element to listen on
13500 * @param {Object} config
13502 Roo.util.ClickRepeater = function(el, config)
13504 this.el = Roo.get(el);
13505 this.el.unselectable();
13507 Roo.apply(this, config);
13512 * Fires when the mouse button is depressed.
13513 * @param {Roo.util.ClickRepeater} this
13515 "mousedown" : true,
13518 * Fires on a specified interval during the time the element is pressed.
13519 * @param {Roo.util.ClickRepeater} this
13524 * Fires when the mouse key is released.
13525 * @param {Roo.util.ClickRepeater} this
13530 this.el.on("mousedown", this.handleMouseDown, this);
13531 if(this.preventDefault || this.stopDefault){
13532 this.el.on("click", function(e){
13533 if(this.preventDefault){
13534 e.preventDefault();
13536 if(this.stopDefault){
13542 // allow inline handler
13544 this.on("click", this.handler, this.scope || this);
13547 Roo.util.ClickRepeater.superclass.constructor.call(this);
13550 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13553 preventDefault : true,
13554 stopDefault : false,
13558 handleMouseDown : function(){
13559 clearTimeout(this.timer);
13561 if(this.pressClass){
13562 this.el.addClass(this.pressClass);
13564 this.mousedownTime = new Date();
13566 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13567 this.el.on("mouseout", this.handleMouseOut, this);
13569 this.fireEvent("mousedown", this);
13570 this.fireEvent("click", this);
13572 this.timer = this.click.defer(this.delay || this.interval, this);
13576 click : function(){
13577 this.fireEvent("click", this);
13578 this.timer = this.click.defer(this.getInterval(), this);
13582 getInterval: function(){
13583 if(!this.accelerate){
13584 return this.interval;
13586 var pressTime = this.mousedownTime.getElapsed();
13587 if(pressTime < 500){
13589 }else if(pressTime < 1700){
13591 }else if(pressTime < 2600){
13593 }else if(pressTime < 3500){
13595 }else if(pressTime < 4400){
13597 }else if(pressTime < 5300){
13599 }else if(pressTime < 6200){
13607 handleMouseOut : function(){
13608 clearTimeout(this.timer);
13609 if(this.pressClass){
13610 this.el.removeClass(this.pressClass);
13612 this.el.on("mouseover", this.handleMouseReturn, this);
13616 handleMouseReturn : function(){
13617 this.el.un("mouseover", this.handleMouseReturn);
13618 if(this.pressClass){
13619 this.el.addClass(this.pressClass);
13625 handleMouseUp : function(){
13626 clearTimeout(this.timer);
13627 this.el.un("mouseover", this.handleMouseReturn);
13628 this.el.un("mouseout", this.handleMouseOut);
13629 Roo.get(document).un("mouseup", this.handleMouseUp);
13630 this.el.removeClass(this.pressClass);
13631 this.fireEvent("mouseup", this);
13635 * Ext JS Library 1.1.1
13636 * Copyright(c) 2006-2007, Ext JS, LLC.
13638 * Originally Released Under LGPL - original licence link has changed is not relivant.
13641 * <script type="text/javascript">
13646 * @class Roo.KeyNav
13647 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13648 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13649 * way to implement custom navigation schemes for any UI component.</p>
13650 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13651 * pageUp, pageDown, del, home, end. Usage:</p>
13653 var nav = new Roo.KeyNav("my-element", {
13654 "left" : function(e){
13655 this.moveLeft(e.ctrlKey);
13657 "right" : function(e){
13658 this.moveRight(e.ctrlKey);
13660 "enter" : function(e){
13667 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13668 * @param {Object} config The config
13670 Roo.KeyNav = function(el, config){
13671 this.el = Roo.get(el);
13672 Roo.apply(this, config);
13673 if(!this.disabled){
13674 this.disabled = true;
13679 Roo.KeyNav.prototype = {
13681 * @cfg {Boolean} disabled
13682 * True to disable this KeyNav instance (defaults to false)
13686 * @cfg {String} defaultEventAction
13687 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13688 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13689 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13691 defaultEventAction: "stopEvent",
13693 * @cfg {Boolean} forceKeyDown
13694 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13695 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13696 * handle keydown instead of keypress.
13698 forceKeyDown : false,
13701 prepareEvent : function(e){
13702 var k = e.getKey();
13703 var h = this.keyToHandler[k];
13704 //if(h && this[h]){
13705 // e.stopPropagation();
13707 if(Roo.isSafari && h && k >= 37 && k <= 40){
13713 relay : function(e){
13714 var k = e.getKey();
13715 var h = this.keyToHandler[k];
13717 if(this.doRelay(e, this[h], h) !== true){
13718 e[this.defaultEventAction]();
13724 doRelay : function(e, h, hname){
13725 return h.call(this.scope || this, e);
13728 // possible handlers
13742 // quick lookup hash
13759 * Enable this KeyNav
13761 enable: function(){
13763 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13764 // the EventObject will normalize Safari automatically
13765 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13766 this.el.on("keydown", this.relay, this);
13768 this.el.on("keydown", this.prepareEvent, this);
13769 this.el.on("keypress", this.relay, this);
13771 this.disabled = false;
13776 * Disable this KeyNav
13778 disable: function(){
13779 if(!this.disabled){
13780 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13781 this.el.un("keydown", this.relay);
13783 this.el.un("keydown", this.prepareEvent);
13784 this.el.un("keypress", this.relay);
13786 this.disabled = true;
13791 * Ext JS Library 1.1.1
13792 * Copyright(c) 2006-2007, Ext JS, LLC.
13794 * Originally Released Under LGPL - original licence link has changed is not relivant.
13797 * <script type="text/javascript">
13802 * @class Roo.KeyMap
13803 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13804 * The constructor accepts the same config object as defined by {@link #addBinding}.
13805 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13806 * combination it will call the function with this signature (if the match is a multi-key
13807 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13808 * A KeyMap can also handle a string representation of keys.<br />
13811 // map one key by key code
13812 var map = new Roo.KeyMap("my-element", {
13813 key: 13, // or Roo.EventObject.ENTER
13818 // map multiple keys to one action by string
13819 var map = new Roo.KeyMap("my-element", {
13825 // map multiple keys to multiple actions by strings and array of codes
13826 var map = new Roo.KeyMap("my-element", [
13829 fn: function(){ alert("Return was pressed"); }
13832 fn: function(){ alert('a, b or c was pressed'); }
13837 fn: function(){ alert('Control + shift + tab was pressed.'); }
13841 * <b>Note: A KeyMap starts enabled</b>
13843 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13844 * @param {Object} config The config (see {@link #addBinding})
13845 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13847 Roo.KeyMap = function(el, config, eventName){
13848 this.el = Roo.get(el);
13849 this.eventName = eventName || "keydown";
13850 this.bindings = [];
13852 this.addBinding(config);
13857 Roo.KeyMap.prototype = {
13859 * True to stop the event from bubbling and prevent the default browser action if the
13860 * key was handled by the KeyMap (defaults to false)
13866 * Add a new binding to this KeyMap. The following config object properties are supported:
13868 Property Type Description
13869 ---------- --------------- ----------------------------------------------------------------------
13870 key String/Array A single keycode or an array of keycodes to handle
13871 shift Boolean True to handle key only when shift is pressed (defaults to false)
13872 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13873 alt Boolean True to handle key only when alt is pressed (defaults to false)
13874 fn Function The function to call when KeyMap finds the expected key combination
13875 scope Object The scope of the callback function
13881 var map = new Roo.KeyMap(document, {
13882 key: Roo.EventObject.ENTER,
13887 //Add a new binding to the existing KeyMap later
13895 * @param {Object/Array} config A single KeyMap config or an array of configs
13897 addBinding : function(config){
13898 if(config instanceof Array){
13899 for(var i = 0, len = config.length; i < len; i++){
13900 this.addBinding(config[i]);
13904 var keyCode = config.key,
13905 shift = config.shift,
13906 ctrl = config.ctrl,
13909 scope = config.scope;
13910 if(typeof keyCode == "string"){
13912 var keyString = keyCode.toUpperCase();
13913 for(var j = 0, len = keyString.length; j < len; j++){
13914 ks.push(keyString.charCodeAt(j));
13918 var keyArray = keyCode instanceof Array;
13919 var handler = function(e){
13920 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13921 var k = e.getKey();
13923 for(var i = 0, len = keyCode.length; i < len; i++){
13924 if(keyCode[i] == k){
13925 if(this.stopEvent){
13928 fn.call(scope || window, k, e);
13934 if(this.stopEvent){
13937 fn.call(scope || window, k, e);
13942 this.bindings.push(handler);
13946 * Shorthand for adding a single key listener
13947 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13948 * following options:
13949 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13950 * @param {Function} fn The function to call
13951 * @param {Object} scope (optional) The scope of the function
13953 on : function(key, fn, scope){
13954 var keyCode, shift, ctrl, alt;
13955 if(typeof key == "object" && !(key instanceof Array)){
13974 handleKeyDown : function(e){
13975 if(this.enabled){ //just in case
13976 var b = this.bindings;
13977 for(var i = 0, len = b.length; i < len; i++){
13978 b[i].call(this, e);
13984 * Returns true if this KeyMap is enabled
13985 * @return {Boolean}
13987 isEnabled : function(){
13988 return this.enabled;
13992 * Enables this KeyMap
13994 enable: function(){
13996 this.el.on(this.eventName, this.handleKeyDown, this);
13997 this.enabled = true;
14002 * Disable this KeyMap
14004 disable: function(){
14006 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14007 this.enabled = false;
14012 * Ext JS Library 1.1.1
14013 * Copyright(c) 2006-2007, Ext JS, LLC.
14015 * Originally Released Under LGPL - original licence link has changed is not relivant.
14018 * <script type="text/javascript">
14023 * @class Roo.util.TextMetrics
14024 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14025 * wide, in pixels, a given block of text will be.
14028 Roo.util.TextMetrics = function(){
14032 * Measures the size of the specified text
14033 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14034 * that can affect the size of the rendered text
14035 * @param {String} text The text to measure
14036 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14037 * in order to accurately measure the text height
14038 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14040 measure : function(el, text, fixedWidth){
14042 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14045 shared.setFixedWidth(fixedWidth || 'auto');
14046 return shared.getSize(text);
14050 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14051 * the overhead of multiple calls to initialize the style properties on each measurement.
14052 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14053 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14054 * in order to accurately measure the text height
14055 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14057 createInstance : function(el, fixedWidth){
14058 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14065 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14066 var ml = new Roo.Element(document.createElement('div'));
14067 document.body.appendChild(ml.dom);
14068 ml.position('absolute');
14069 ml.setLeftTop(-1000, -1000);
14073 ml.setWidth(fixedWidth);
14078 * Returns the size of the specified text based on the internal element's style and width properties
14079 * @memberOf Roo.util.TextMetrics.Instance#
14080 * @param {String} text The text to measure
14081 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14083 getSize : function(text){
14085 var s = ml.getSize();
14091 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14092 * that can affect the size of the rendered text
14093 * @memberOf Roo.util.TextMetrics.Instance#
14094 * @param {String/HTMLElement} el The element, dom node or id
14096 bind : function(el){
14098 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14103 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14104 * to set a fixed width in order to accurately measure the text height.
14105 * @memberOf Roo.util.TextMetrics.Instance#
14106 * @param {Number} width The width to set on the element
14108 setFixedWidth : function(width){
14109 ml.setWidth(width);
14113 * Returns the measured width of the specified text
14114 * @memberOf Roo.util.TextMetrics.Instance#
14115 * @param {String} text The text to measure
14116 * @return {Number} width The width in pixels
14118 getWidth : function(text){
14119 ml.dom.style.width = 'auto';
14120 return this.getSize(text).width;
14124 * Returns the measured height of the specified text. For multiline text, be sure to call
14125 * {@link #setFixedWidth} if necessary.
14126 * @memberOf Roo.util.TextMetrics.Instance#
14127 * @param {String} text The text to measure
14128 * @return {Number} height The height in pixels
14130 getHeight : function(text){
14131 return this.getSize(text).height;
14135 instance.bind(bindTo);
14140 // backwards compat
14141 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14143 * Ext JS Library 1.1.1
14144 * Copyright(c) 2006-2007, Ext JS, LLC.
14146 * Originally Released Under LGPL - original licence link has changed is not relivant.
14149 * <script type="text/javascript">
14153 * @class Roo.state.Provider
14154 * Abstract base class for state provider implementations. This class provides methods
14155 * for encoding and decoding <b>typed</b> variables including dates and defines the
14156 * Provider interface.
14158 Roo.state.Provider = function(){
14160 * @event statechange
14161 * Fires when a state change occurs.
14162 * @param {Provider} this This state provider
14163 * @param {String} key The state key which was changed
14164 * @param {String} value The encoded value for the state
14167 "statechange": true
14170 Roo.state.Provider.superclass.constructor.call(this);
14172 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14174 * Returns the current value for a key
14175 * @param {String} name The key name
14176 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14177 * @return {Mixed} The state data
14179 get : function(name, defaultValue){
14180 return typeof this.state[name] == "undefined" ?
14181 defaultValue : this.state[name];
14185 * Clears a value from the state
14186 * @param {String} name The key name
14188 clear : function(name){
14189 delete this.state[name];
14190 this.fireEvent("statechange", this, name, null);
14194 * Sets the value for a key
14195 * @param {String} name The key name
14196 * @param {Mixed} value The value to set
14198 set : function(name, value){
14199 this.state[name] = value;
14200 this.fireEvent("statechange", this, name, value);
14204 * Decodes a string previously encoded with {@link #encodeValue}.
14205 * @param {String} value The value to decode
14206 * @return {Mixed} The decoded value
14208 decodeValue : function(cookie){
14209 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14210 var matches = re.exec(unescape(cookie));
14211 if(!matches || !matches[1]) return; // non state cookie
14212 var type = matches[1];
14213 var v = matches[2];
14216 return parseFloat(v);
14218 return new Date(Date.parse(v));
14223 var values = v.split("^");
14224 for(var i = 0, len = values.length; i < len; i++){
14225 all.push(this.decodeValue(values[i]));
14230 var values = v.split("^");
14231 for(var i = 0, len = values.length; i < len; i++){
14232 var kv = values[i].split("=");
14233 all[kv[0]] = this.decodeValue(kv[1]);
14242 * Encodes a value including type information. Decode with {@link #decodeValue}.
14243 * @param {Mixed} value The value to encode
14244 * @return {String} The encoded value
14246 encodeValue : function(v){
14248 if(typeof v == "number"){
14250 }else if(typeof v == "boolean"){
14251 enc = "b:" + (v ? "1" : "0");
14252 }else if(v instanceof Date){
14253 enc = "d:" + v.toGMTString();
14254 }else if(v instanceof Array){
14256 for(var i = 0, len = v.length; i < len; i++){
14257 flat += this.encodeValue(v[i]);
14258 if(i != len-1) flat += "^";
14261 }else if(typeof v == "object"){
14264 if(typeof v[key] != "function"){
14265 flat += key + "=" + this.encodeValue(v[key]) + "^";
14268 enc = "o:" + flat.substring(0, flat.length-1);
14272 return escape(enc);
14278 * Ext JS Library 1.1.1
14279 * Copyright(c) 2006-2007, Ext JS, LLC.
14281 * Originally Released Under LGPL - original licence link has changed is not relivant.
14284 * <script type="text/javascript">
14287 * @class Roo.state.Manager
14288 * This is the global state manager. By default all components that are "state aware" check this class
14289 * for state information if you don't pass them a custom state provider. In order for this class
14290 * to be useful, it must be initialized with a provider when your application initializes.
14292 // in your initialization function
14294 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14296 // supposed you have a {@link Roo.BorderLayout}
14297 var layout = new Roo.BorderLayout(...);
14298 layout.restoreState();
14299 // or a {Roo.BasicDialog}
14300 var dialog = new Roo.BasicDialog(...);
14301 dialog.restoreState();
14305 Roo.state.Manager = function(){
14306 var provider = new Roo.state.Provider();
14310 * Configures the default state provider for your application
14311 * @param {Provider} stateProvider The state provider to set
14313 setProvider : function(stateProvider){
14314 provider = stateProvider;
14318 * Returns the current value for a key
14319 * @param {String} name The key name
14320 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14321 * @return {Mixed} The state data
14323 get : function(key, defaultValue){
14324 return provider.get(key, defaultValue);
14328 * Sets the value for a key
14329 * @param {String} name The key name
14330 * @param {Mixed} value The state data
14332 set : function(key, value){
14333 provider.set(key, value);
14337 * Clears a value from the state
14338 * @param {String} name The key name
14340 clear : function(key){
14341 provider.clear(key);
14345 * Gets the currently configured state provider
14346 * @return {Provider} The state provider
14348 getProvider : function(){
14355 * Ext JS Library 1.1.1
14356 * Copyright(c) 2006-2007, Ext JS, LLC.
14358 * Originally Released Under LGPL - original licence link has changed is not relivant.
14361 * <script type="text/javascript">
14364 * @class Roo.state.CookieProvider
14365 * @extends Roo.state.Provider
14366 * The default Provider implementation which saves state via cookies.
14369 var cp = new Roo.state.CookieProvider({
14371 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14372 domain: "roojs.com"
14374 Roo.state.Manager.setProvider(cp);
14376 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14377 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14378 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14379 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14380 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14381 * domain the page is running on including the 'www' like 'www.roojs.com')
14382 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14384 * Create a new CookieProvider
14385 * @param {Object} config The configuration object
14387 Roo.state.CookieProvider = function(config){
14388 Roo.state.CookieProvider.superclass.constructor.call(this);
14390 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14391 this.domain = null;
14392 this.secure = false;
14393 Roo.apply(this, config);
14394 this.state = this.readCookies();
14397 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14399 set : function(name, value){
14400 if(typeof value == "undefined" || value === null){
14404 this.setCookie(name, value);
14405 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14409 clear : function(name){
14410 this.clearCookie(name);
14411 Roo.state.CookieProvider.superclass.clear.call(this, name);
14415 readCookies : function(){
14417 var c = document.cookie + ";";
14418 var re = /\s?(.*?)=(.*?);/g;
14420 while((matches = re.exec(c)) != null){
14421 var name = matches[1];
14422 var value = matches[2];
14423 if(name && name.substring(0,3) == "ys-"){
14424 cookies[name.substr(3)] = this.decodeValue(value);
14431 setCookie : function(name, value){
14432 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14433 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14434 ((this.path == null) ? "" : ("; path=" + this.path)) +
14435 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14436 ((this.secure == true) ? "; secure" : "");
14440 clearCookie : function(name){
14441 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14442 ((this.path == null) ? "" : ("; path=" + this.path)) +
14443 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14444 ((this.secure == true) ? "; secure" : "");
14448 * Ext JS Library 1.1.1
14449 * Copyright(c) 2006-2007, Ext JS, LLC.
14451 * Originally Released Under LGPL - original licence link has changed is not relivant.
14454 * <script type="text/javascript">
14460 * These classes are derivatives of the similarly named classes in the YUI Library.
14461 * The original license:
14462 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14463 * Code licensed under the BSD License:
14464 * http://developer.yahoo.net/yui/license.txt
14469 var Event=Roo.EventManager;
14470 var Dom=Roo.lib.Dom;
14473 * @class Roo.dd.DragDrop
14474 * @extends Roo.util.Observable
14475 * Defines the interface and base operation of items that that can be
14476 * dragged or can be drop targets. It was designed to be extended, overriding
14477 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14478 * Up to three html elements can be associated with a DragDrop instance:
14480 * <li>linked element: the element that is passed into the constructor.
14481 * This is the element which defines the boundaries for interaction with
14482 * other DragDrop objects.</li>
14483 * <li>handle element(s): The drag operation only occurs if the element that
14484 * was clicked matches a handle element. By default this is the linked
14485 * element, but there are times that you will want only a portion of the
14486 * linked element to initiate the drag operation, and the setHandleElId()
14487 * method provides a way to define this.</li>
14488 * <li>drag element: this represents the element that would be moved along
14489 * with the cursor during a drag operation. By default, this is the linked
14490 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14491 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14494 * This class should not be instantiated until the onload event to ensure that
14495 * the associated elements are available.
14496 * The following would define a DragDrop obj that would interact with any
14497 * other DragDrop obj in the "group1" group:
14499 * dd = new Roo.dd.DragDrop("div1", "group1");
14501 * Since none of the event handlers have been implemented, nothing would
14502 * actually happen if you were to run the code above. Normally you would
14503 * override this class or one of the default implementations, but you can
14504 * also override the methods you want on an instance of the class...
14506 * dd.onDragDrop = function(e, id) {
14507 * alert("dd was dropped on " + id);
14511 * @param {String} id of the element that is linked to this instance
14512 * @param {String} sGroup the group of related DragDrop objects
14513 * @param {object} config an object containing configurable attributes
14514 * Valid properties for DragDrop:
14515 * padding, isTarget, maintainOffset, primaryButtonOnly
14517 Roo.dd.DragDrop = function(id, sGroup, config) {
14519 this.init(id, sGroup, config);
14524 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14527 * The id of the element associated with this object. This is what we
14528 * refer to as the "linked element" because the size and position of
14529 * this element is used to determine when the drag and drop objects have
14537 * Configuration attributes passed into the constructor
14544 * The id of the element that will be dragged. By default this is same
14545 * as the linked element , but could be changed to another element. Ex:
14547 * @property dragElId
14554 * the id of the element that initiates the drag operation. By default
14555 * this is the linked element, but could be changed to be a child of this
14556 * element. This lets us do things like only starting the drag when the
14557 * header element within the linked html element is clicked.
14558 * @property handleElId
14565 * An associative array of HTML tags that will be ignored if clicked.
14566 * @property invalidHandleTypes
14567 * @type {string: string}
14569 invalidHandleTypes: null,
14572 * An associative array of ids for elements that will be ignored if clicked
14573 * @property invalidHandleIds
14574 * @type {string: string}
14576 invalidHandleIds: null,
14579 * An indexted array of css class names for elements that will be ignored
14581 * @property invalidHandleClasses
14584 invalidHandleClasses: null,
14587 * The linked element's absolute X position at the time the drag was
14589 * @property startPageX
14596 * The linked element's absolute X position at the time the drag was
14598 * @property startPageY
14605 * The group defines a logical collection of DragDrop objects that are
14606 * related. Instances only get events when interacting with other
14607 * DragDrop object in the same group. This lets us define multiple
14608 * groups using a single DragDrop subclass if we want.
14610 * @type {string: string}
14615 * Individual drag/drop instances can be locked. This will prevent
14616 * onmousedown start drag.
14624 * Lock this instance
14627 lock: function() { this.locked = true; },
14630 * Unlock this instace
14633 unlock: function() { this.locked = false; },
14636 * By default, all insances can be a drop target. This can be disabled by
14637 * setting isTarget to false.
14644 * The padding configured for this drag and drop object for calculating
14645 * the drop zone intersection with this object.
14652 * Cached reference to the linked element
14653 * @property _domRef
14659 * Internal typeof flag
14660 * @property __ygDragDrop
14663 __ygDragDrop: true,
14666 * Set to true when horizontal contraints are applied
14667 * @property constrainX
14674 * Set to true when vertical contraints are applied
14675 * @property constrainY
14682 * The left constraint
14690 * The right constraint
14698 * The up constraint
14707 * The down constraint
14715 * Maintain offsets when we resetconstraints. Set to true when you want
14716 * the position of the element relative to its parent to stay the same
14717 * when the page changes
14719 * @property maintainOffset
14722 maintainOffset: false,
14725 * Array of pixel locations the element will snap to if we specified a
14726 * horizontal graduation/interval. This array is generated automatically
14727 * when you define a tick interval.
14734 * Array of pixel locations the element will snap to if we specified a
14735 * vertical graduation/interval. This array is generated automatically
14736 * when you define a tick interval.
14743 * By default the drag and drop instance will only respond to the primary
14744 * button click (left button for a right-handed mouse). Set to true to
14745 * allow drag and drop to start with any mouse click that is propogated
14747 * @property primaryButtonOnly
14750 primaryButtonOnly: true,
14753 * The availabe property is false until the linked dom element is accessible.
14754 * @property available
14760 * By default, drags can only be initiated if the mousedown occurs in the
14761 * region the linked element is. This is done in part to work around a
14762 * bug in some browsers that mis-report the mousedown if the previous
14763 * mouseup happened outside of the window. This property is set to true
14764 * if outer handles are defined.
14766 * @property hasOuterHandles
14770 hasOuterHandles: false,
14773 * Code that executes immediately before the startDrag event
14774 * @method b4StartDrag
14777 b4StartDrag: function(x, y) { },
14780 * Abstract method called after a drag/drop object is clicked
14781 * and the drag or mousedown time thresholds have beeen met.
14782 * @method startDrag
14783 * @param {int} X click location
14784 * @param {int} Y click location
14786 startDrag: function(x, y) { /* override this */ },
14789 * Code that executes immediately before the onDrag event
14793 b4Drag: function(e) { },
14796 * Abstract method called during the onMouseMove event while dragging an
14799 * @param {Event} e the mousemove event
14801 onDrag: function(e) { /* override this */ },
14804 * Abstract method called when this element fist begins hovering over
14805 * another DragDrop obj
14806 * @method onDragEnter
14807 * @param {Event} e the mousemove event
14808 * @param {String|DragDrop[]} id In POINT mode, the element
14809 * id this is hovering over. In INTERSECT mode, an array of one or more
14810 * dragdrop items being hovered over.
14812 onDragEnter: function(e, id) { /* override this */ },
14815 * Code that executes immediately before the onDragOver event
14816 * @method b4DragOver
14819 b4DragOver: function(e) { },
14822 * Abstract method called when this element is hovering over another
14824 * @method onDragOver
14825 * @param {Event} e the mousemove event
14826 * @param {String|DragDrop[]} id In POINT mode, the element
14827 * id this is hovering over. In INTERSECT mode, an array of dd items
14828 * being hovered over.
14830 onDragOver: function(e, id) { /* override this */ },
14833 * Code that executes immediately before the onDragOut event
14834 * @method b4DragOut
14837 b4DragOut: function(e) { },
14840 * Abstract method called when we are no longer hovering over an element
14841 * @method onDragOut
14842 * @param {Event} e the mousemove event
14843 * @param {String|DragDrop[]} id In POINT mode, the element
14844 * id this was hovering over. In INTERSECT mode, an array of dd items
14845 * that the mouse is no longer over.
14847 onDragOut: function(e, id) { /* override this */ },
14850 * Code that executes immediately before the onDragDrop event
14851 * @method b4DragDrop
14854 b4DragDrop: function(e) { },
14857 * Abstract method called when this item is dropped on another DragDrop
14859 * @method onDragDrop
14860 * @param {Event} e the mouseup event
14861 * @param {String|DragDrop[]} id In POINT mode, the element
14862 * id this was dropped on. In INTERSECT mode, an array of dd items this
14865 onDragDrop: function(e, id) { /* override this */ },
14868 * Abstract method called when this item is dropped on an area with no
14870 * @method onInvalidDrop
14871 * @param {Event} e the mouseup event
14873 onInvalidDrop: function(e) { /* override this */ },
14876 * Code that executes immediately before the endDrag event
14877 * @method b4EndDrag
14880 b4EndDrag: function(e) { },
14883 * Fired when we are done dragging the object
14885 * @param {Event} e the mouseup event
14887 endDrag: function(e) { /* override this */ },
14890 * Code executed immediately before the onMouseDown event
14891 * @method b4MouseDown
14892 * @param {Event} e the mousedown event
14895 b4MouseDown: function(e) { },
14898 * Event handler that fires when a drag/drop obj gets a mousedown
14899 * @method onMouseDown
14900 * @param {Event} e the mousedown event
14902 onMouseDown: function(e) { /* override this */ },
14905 * Event handler that fires when a drag/drop obj gets a mouseup
14906 * @method onMouseUp
14907 * @param {Event} e the mouseup event
14909 onMouseUp: function(e) { /* override this */ },
14912 * Override the onAvailable method to do what is needed after the initial
14913 * position was determined.
14914 * @method onAvailable
14916 onAvailable: function () {
14920 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14923 defaultPadding : {left:0, right:0, top:0, bottom:0},
14926 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14930 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14931 { dragElId: "existingProxyDiv" });
14932 dd.startDrag = function(){
14933 this.constrainTo("parent-id");
14936 * Or you can initalize it using the {@link Roo.Element} object:
14938 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14939 startDrag : function(){
14940 this.constrainTo("parent-id");
14944 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14945 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14946 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14947 * an object containing the sides to pad. For example: {right:10, bottom:10}
14948 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14950 constrainTo : function(constrainTo, pad, inContent){
14951 if(typeof pad == "number"){
14952 pad = {left: pad, right:pad, top:pad, bottom:pad};
14954 pad = pad || this.defaultPadding;
14955 var b = Roo.get(this.getEl()).getBox();
14956 var ce = Roo.get(constrainTo);
14957 var s = ce.getScroll();
14958 var c, cd = ce.dom;
14959 if(cd == document.body){
14960 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14963 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14967 var topSpace = b.y - c.y;
14968 var leftSpace = b.x - c.x;
14970 this.resetConstraints();
14971 this.setXConstraint(leftSpace - (pad.left||0), // left
14972 c.width - leftSpace - b.width - (pad.right||0) //right
14974 this.setYConstraint(topSpace - (pad.top||0), //top
14975 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14980 * Returns a reference to the linked element
14982 * @return {HTMLElement} the html element
14984 getEl: function() {
14985 if (!this._domRef) {
14986 this._domRef = Roo.getDom(this.id);
14989 return this._domRef;
14993 * Returns a reference to the actual element to drag. By default this is
14994 * the same as the html element, but it can be assigned to another
14995 * element. An example of this can be found in Roo.dd.DDProxy
14996 * @method getDragEl
14997 * @return {HTMLElement} the html element
14999 getDragEl: function() {
15000 return Roo.getDom(this.dragElId);
15004 * Sets up the DragDrop object. Must be called in the constructor of any
15005 * Roo.dd.DragDrop subclass
15007 * @param id the id of the linked element
15008 * @param {String} sGroup the group of related items
15009 * @param {object} config configuration attributes
15011 init: function(id, sGroup, config) {
15012 this.initTarget(id, sGroup, config);
15013 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15014 // Event.on(this.id, "selectstart", Event.preventDefault);
15018 * Initializes Targeting functionality only... the object does not
15019 * get a mousedown handler.
15020 * @method initTarget
15021 * @param id the id of the linked element
15022 * @param {String} sGroup the group of related items
15023 * @param {object} config configuration attributes
15025 initTarget: function(id, sGroup, config) {
15027 // configuration attributes
15028 this.config = config || {};
15030 // create a local reference to the drag and drop manager
15031 this.DDM = Roo.dd.DDM;
15032 // initialize the groups array
15035 // assume that we have an element reference instead of an id if the
15036 // parameter is not a string
15037 if (typeof id !== "string") {
15044 // add to an interaction group
15045 this.addToGroup((sGroup) ? sGroup : "default");
15047 // We don't want to register this as the handle with the manager
15048 // so we just set the id rather than calling the setter.
15049 this.handleElId = id;
15051 // the linked element is the element that gets dragged by default
15052 this.setDragElId(id);
15054 // by default, clicked anchors will not start drag operations.
15055 this.invalidHandleTypes = { A: "A" };
15056 this.invalidHandleIds = {};
15057 this.invalidHandleClasses = [];
15059 this.applyConfig();
15061 this.handleOnAvailable();
15065 * Applies the configuration parameters that were passed into the constructor.
15066 * This is supposed to happen at each level through the inheritance chain. So
15067 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15068 * DragDrop in order to get all of the parameters that are available in
15070 * @method applyConfig
15072 applyConfig: function() {
15074 // configurable properties:
15075 // padding, isTarget, maintainOffset, primaryButtonOnly
15076 this.padding = this.config.padding || [0, 0, 0, 0];
15077 this.isTarget = (this.config.isTarget !== false);
15078 this.maintainOffset = (this.config.maintainOffset);
15079 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15084 * Executed when the linked element is available
15085 * @method handleOnAvailable
15088 handleOnAvailable: function() {
15089 this.available = true;
15090 this.resetConstraints();
15091 this.onAvailable();
15095 * Configures the padding for the target zone in px. Effectively expands
15096 * (or reduces) the virtual object size for targeting calculations.
15097 * Supports css-style shorthand; if only one parameter is passed, all sides
15098 * will have that padding, and if only two are passed, the top and bottom
15099 * will have the first param, the left and right the second.
15100 * @method setPadding
15101 * @param {int} iTop Top pad
15102 * @param {int} iRight Right pad
15103 * @param {int} iBot Bot pad
15104 * @param {int} iLeft Left pad
15106 setPadding: function(iTop, iRight, iBot, iLeft) {
15107 // this.padding = [iLeft, iRight, iTop, iBot];
15108 if (!iRight && 0 !== iRight) {
15109 this.padding = [iTop, iTop, iTop, iTop];
15110 } else if (!iBot && 0 !== iBot) {
15111 this.padding = [iTop, iRight, iTop, iRight];
15113 this.padding = [iTop, iRight, iBot, iLeft];
15118 * Stores the initial placement of the linked element.
15119 * @method setInitialPosition
15120 * @param {int} diffX the X offset, default 0
15121 * @param {int} diffY the Y offset, default 0
15123 setInitPosition: function(diffX, diffY) {
15124 var el = this.getEl();
15126 if (!this.DDM.verifyEl(el)) {
15130 var dx = diffX || 0;
15131 var dy = diffY || 0;
15133 var p = Dom.getXY( el );
15135 this.initPageX = p[0] - dx;
15136 this.initPageY = p[1] - dy;
15138 this.lastPageX = p[0];
15139 this.lastPageY = p[1];
15142 this.setStartPosition(p);
15146 * Sets the start position of the element. This is set when the obj
15147 * is initialized, the reset when a drag is started.
15148 * @method setStartPosition
15149 * @param pos current position (from previous lookup)
15152 setStartPosition: function(pos) {
15153 var p = pos || Dom.getXY( this.getEl() );
15154 this.deltaSetXY = null;
15156 this.startPageX = p[0];
15157 this.startPageY = p[1];
15161 * Add this instance to a group of related drag/drop objects. All
15162 * instances belong to at least one group, and can belong to as many
15163 * groups as needed.
15164 * @method addToGroup
15165 * @param sGroup {string} the name of the group
15167 addToGroup: function(sGroup) {
15168 this.groups[sGroup] = true;
15169 this.DDM.regDragDrop(this, sGroup);
15173 * Remove's this instance from the supplied interaction group
15174 * @method removeFromGroup
15175 * @param {string} sGroup The group to drop
15177 removeFromGroup: function(sGroup) {
15178 if (this.groups[sGroup]) {
15179 delete this.groups[sGroup];
15182 this.DDM.removeDDFromGroup(this, sGroup);
15186 * Allows you to specify that an element other than the linked element
15187 * will be moved with the cursor during a drag
15188 * @method setDragElId
15189 * @param id {string} the id of the element that will be used to initiate the drag
15191 setDragElId: function(id) {
15192 this.dragElId = id;
15196 * Allows you to specify a child of the linked element that should be
15197 * used to initiate the drag operation. An example of this would be if
15198 * you have a content div with text and links. Clicking anywhere in the
15199 * content area would normally start the drag operation. Use this method
15200 * to specify that an element inside of the content div is the element
15201 * that starts the drag operation.
15202 * @method setHandleElId
15203 * @param id {string} the id of the element that will be used to
15204 * initiate the drag.
15206 setHandleElId: function(id) {
15207 if (typeof id !== "string") {
15210 this.handleElId = id;
15211 this.DDM.regHandle(this.id, id);
15215 * Allows you to set an element outside of the linked element as a drag
15217 * @method setOuterHandleElId
15218 * @param id the id of the element that will be used to initiate the drag
15220 setOuterHandleElId: function(id) {
15221 if (typeof id !== "string") {
15224 Event.on(id, "mousedown",
15225 this.handleMouseDown, this);
15226 this.setHandleElId(id);
15228 this.hasOuterHandles = true;
15232 * Remove all drag and drop hooks for this element
15235 unreg: function() {
15236 Event.un(this.id, "mousedown",
15237 this.handleMouseDown);
15238 this._domRef = null;
15239 this.DDM._remove(this);
15242 destroy : function(){
15247 * Returns true if this instance is locked, or the drag drop mgr is locked
15248 * (meaning that all drag/drop is disabled on the page.)
15250 * @return {boolean} true if this obj or all drag/drop is locked, else
15253 isLocked: function() {
15254 return (this.DDM.isLocked() || this.locked);
15258 * Fired when this object is clicked
15259 * @method handleMouseDown
15261 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15264 handleMouseDown: function(e, oDD){
15265 if (this.primaryButtonOnly && e.button != 0) {
15269 if (this.isLocked()) {
15273 this.DDM.refreshCache(this.groups);
15275 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15276 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15278 if (this.clickValidator(e)) {
15280 // set the initial element position
15281 this.setStartPosition();
15284 this.b4MouseDown(e);
15285 this.onMouseDown(e);
15287 this.DDM.handleMouseDown(e, this);
15289 this.DDM.stopEvent(e);
15297 clickValidator: function(e) {
15298 var target = e.getTarget();
15299 return ( this.isValidHandleChild(target) &&
15300 (this.id == this.handleElId ||
15301 this.DDM.handleWasClicked(target, this.id)) );
15305 * Allows you to specify a tag name that should not start a drag operation
15306 * when clicked. This is designed to facilitate embedding links within a
15307 * drag handle that do something other than start the drag.
15308 * @method addInvalidHandleType
15309 * @param {string} tagName the type of element to exclude
15311 addInvalidHandleType: function(tagName) {
15312 var type = tagName.toUpperCase();
15313 this.invalidHandleTypes[type] = type;
15317 * Lets you to specify an element id for a child of a drag handle
15318 * that should not initiate a drag
15319 * @method addInvalidHandleId
15320 * @param {string} id the element id of the element you wish to ignore
15322 addInvalidHandleId: function(id) {
15323 if (typeof id !== "string") {
15326 this.invalidHandleIds[id] = id;
15330 * Lets you specify a css class of elements that will not initiate a drag
15331 * @method addInvalidHandleClass
15332 * @param {string} cssClass the class of the elements you wish to ignore
15334 addInvalidHandleClass: function(cssClass) {
15335 this.invalidHandleClasses.push(cssClass);
15339 * Unsets an excluded tag name set by addInvalidHandleType
15340 * @method removeInvalidHandleType
15341 * @param {string} tagName the type of element to unexclude
15343 removeInvalidHandleType: function(tagName) {
15344 var type = tagName.toUpperCase();
15345 // this.invalidHandleTypes[type] = null;
15346 delete this.invalidHandleTypes[type];
15350 * Unsets an invalid handle id
15351 * @method removeInvalidHandleId
15352 * @param {string} id the id of the element to re-enable
15354 removeInvalidHandleId: function(id) {
15355 if (typeof id !== "string") {
15358 delete this.invalidHandleIds[id];
15362 * Unsets an invalid css class
15363 * @method removeInvalidHandleClass
15364 * @param {string} cssClass the class of the element(s) you wish to
15367 removeInvalidHandleClass: function(cssClass) {
15368 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15369 if (this.invalidHandleClasses[i] == cssClass) {
15370 delete this.invalidHandleClasses[i];
15376 * Checks the tag exclusion list to see if this click should be ignored
15377 * @method isValidHandleChild
15378 * @param {HTMLElement} node the HTMLElement to evaluate
15379 * @return {boolean} true if this is a valid tag type, false if not
15381 isValidHandleChild: function(node) {
15384 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15387 nodeName = node.nodeName.toUpperCase();
15389 nodeName = node.nodeName;
15391 valid = valid && !this.invalidHandleTypes[nodeName];
15392 valid = valid && !this.invalidHandleIds[node.id];
15394 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15395 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15404 * Create the array of horizontal tick marks if an interval was specified
15405 * in setXConstraint().
15406 * @method setXTicks
15409 setXTicks: function(iStartX, iTickSize) {
15411 this.xTickSize = iTickSize;
15415 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15417 this.xTicks[this.xTicks.length] = i;
15422 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15424 this.xTicks[this.xTicks.length] = i;
15429 this.xTicks.sort(this.DDM.numericSort) ;
15433 * Create the array of vertical tick marks if an interval was specified in
15434 * setYConstraint().
15435 * @method setYTicks
15438 setYTicks: function(iStartY, iTickSize) {
15440 this.yTickSize = iTickSize;
15444 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15446 this.yTicks[this.yTicks.length] = i;
15451 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15453 this.yTicks[this.yTicks.length] = i;
15458 this.yTicks.sort(this.DDM.numericSort) ;
15462 * By default, the element can be dragged any place on the screen. Use
15463 * this method to limit the horizontal travel of the element. Pass in
15464 * 0,0 for the parameters if you want to lock the drag to the y axis.
15465 * @method setXConstraint
15466 * @param {int} iLeft the number of pixels the element can move to the left
15467 * @param {int} iRight the number of pixels the element can move to the
15469 * @param {int} iTickSize optional parameter for specifying that the
15471 * should move iTickSize pixels at a time.
15473 setXConstraint: function(iLeft, iRight, iTickSize) {
15474 this.leftConstraint = iLeft;
15475 this.rightConstraint = iRight;
15477 this.minX = this.initPageX - iLeft;
15478 this.maxX = this.initPageX + iRight;
15479 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15481 this.constrainX = true;
15485 * Clears any constraints applied to this instance. Also clears ticks
15486 * since they can't exist independent of a constraint at this time.
15487 * @method clearConstraints
15489 clearConstraints: function() {
15490 this.constrainX = false;
15491 this.constrainY = false;
15496 * Clears any tick interval defined for this instance
15497 * @method clearTicks
15499 clearTicks: function() {
15500 this.xTicks = null;
15501 this.yTicks = null;
15502 this.xTickSize = 0;
15503 this.yTickSize = 0;
15507 * By default, the element can be dragged any place on the screen. Set
15508 * this to limit the vertical travel of the element. Pass in 0,0 for the
15509 * parameters if you want to lock the drag to the x axis.
15510 * @method setYConstraint
15511 * @param {int} iUp the number of pixels the element can move up
15512 * @param {int} iDown the number of pixels the element can move down
15513 * @param {int} iTickSize optional parameter for specifying that the
15514 * element should move iTickSize pixels at a time.
15516 setYConstraint: function(iUp, iDown, iTickSize) {
15517 this.topConstraint = iUp;
15518 this.bottomConstraint = iDown;
15520 this.minY = this.initPageY - iUp;
15521 this.maxY = this.initPageY + iDown;
15522 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15524 this.constrainY = true;
15529 * resetConstraints must be called if you manually reposition a dd element.
15530 * @method resetConstraints
15531 * @param {boolean} maintainOffset
15533 resetConstraints: function() {
15536 // Maintain offsets if necessary
15537 if (this.initPageX || this.initPageX === 0) {
15538 // figure out how much this thing has moved
15539 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15540 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15542 this.setInitPosition(dx, dy);
15544 // This is the first time we have detected the element's position
15546 this.setInitPosition();
15549 if (this.constrainX) {
15550 this.setXConstraint( this.leftConstraint,
15551 this.rightConstraint,
15555 if (this.constrainY) {
15556 this.setYConstraint( this.topConstraint,
15557 this.bottomConstraint,
15563 * Normally the drag element is moved pixel by pixel, but we can specify
15564 * that it move a number of pixels at a time. This method resolves the
15565 * location when we have it set up like this.
15567 * @param {int} val where we want to place the object
15568 * @param {int[]} tickArray sorted array of valid points
15569 * @return {int} the closest tick
15572 getTick: function(val, tickArray) {
15575 // If tick interval is not defined, it is effectively 1 pixel,
15576 // so we return the value passed to us.
15578 } else if (tickArray[0] >= val) {
15579 // The value is lower than the first tick, so we return the first
15581 return tickArray[0];
15583 for (var i=0, len=tickArray.length; i<len; ++i) {
15585 if (tickArray[next] && tickArray[next] >= val) {
15586 var diff1 = val - tickArray[i];
15587 var diff2 = tickArray[next] - val;
15588 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15592 // The value is larger than the last tick, so we return the last
15594 return tickArray[tickArray.length - 1];
15601 * @return {string} string representation of the dd obj
15603 toString: function() {
15604 return ("DragDrop " + this.id);
15612 * Ext JS Library 1.1.1
15613 * Copyright(c) 2006-2007, Ext JS, LLC.
15615 * Originally Released Under LGPL - original licence link has changed is not relivant.
15618 * <script type="text/javascript">
15623 * The drag and drop utility provides a framework for building drag and drop
15624 * applications. In addition to enabling drag and drop for specific elements,
15625 * the drag and drop elements are tracked by the manager class, and the
15626 * interactions between the various elements are tracked during the drag and
15627 * the implementing code is notified about these important moments.
15630 // Only load the library once. Rewriting the manager class would orphan
15631 // existing drag and drop instances.
15632 if (!Roo.dd.DragDropMgr) {
15635 * @class Roo.dd.DragDropMgr
15636 * DragDropMgr is a singleton that tracks the element interaction for
15637 * all DragDrop items in the window. Generally, you will not call
15638 * this class directly, but it does have helper methods that could
15639 * be useful in your DragDrop implementations.
15642 Roo.dd.DragDropMgr = function() {
15644 var Event = Roo.EventManager;
15649 * Two dimensional Array of registered DragDrop objects. The first
15650 * dimension is the DragDrop item group, the second the DragDrop
15653 * @type {string: string}
15660 * Array of element ids defined as drag handles. Used to determine
15661 * if the element that generated the mousedown event is actually the
15662 * handle and not the html element itself.
15663 * @property handleIds
15664 * @type {string: string}
15671 * the DragDrop object that is currently being dragged
15672 * @property dragCurrent
15680 * the DragDrop object(s) that are being hovered over
15681 * @property dragOvers
15689 * the X distance between the cursor and the object being dragged
15698 * the Y distance between the cursor and the object being dragged
15707 * Flag to determine if we should prevent the default behavior of the
15708 * events we define. By default this is true, but this can be set to
15709 * false if you need the default behavior (not recommended)
15710 * @property preventDefault
15714 preventDefault: true,
15717 * Flag to determine if we should stop the propagation of the events
15718 * we generate. This is true by default but you may want to set it to
15719 * false if the html element contains other features that require the
15721 * @property stopPropagation
15725 stopPropagation: true,
15728 * Internal flag that is set to true when drag and drop has been
15730 * @property initialized
15737 * All drag and drop can be disabled.
15745 * Called the first time an element is registered.
15751 this.initialized = true;
15755 * In point mode, drag and drop interaction is defined by the
15756 * location of the cursor during the drag/drop
15764 * In intersect mode, drag and drop interactio nis defined by the
15765 * overlap of two or more drag and drop objects.
15766 * @property INTERSECT
15773 * The current drag and drop mode. Default: POINT
15781 * Runs method on all drag and drop objects
15782 * @method _execOnAll
15786 _execOnAll: function(sMethod, args) {
15787 for (var i in this.ids) {
15788 for (var j in this.ids[i]) {
15789 var oDD = this.ids[i][j];
15790 if (! this.isTypeOfDD(oDD)) {
15793 oDD[sMethod].apply(oDD, args);
15799 * Drag and drop initialization. Sets up the global event handlers
15804 _onLoad: function() {
15809 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15810 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15811 Event.on(window, "unload", this._onUnload, this, true);
15812 Event.on(window, "resize", this._onResize, this, true);
15813 // Event.on(window, "mouseout", this._test);
15818 * Reset constraints on all drag and drop objs
15819 * @method _onResize
15823 _onResize: function(e) {
15824 this._execOnAll("resetConstraints", []);
15828 * Lock all drag and drop functionality
15832 lock: function() { this.locked = true; },
15835 * Unlock all drag and drop functionality
15839 unlock: function() { this.locked = false; },
15842 * Is drag and drop locked?
15844 * @return {boolean} True if drag and drop is locked, false otherwise.
15847 isLocked: function() { return this.locked; },
15850 * Location cache that is set for all drag drop objects when a drag is
15851 * initiated, cleared when the drag is finished.
15852 * @property locationCache
15859 * Set useCache to false if you want to force object the lookup of each
15860 * drag and drop linked element constantly during a drag.
15861 * @property useCache
15868 * The number of pixels that the mouse needs to move after the
15869 * mousedown before the drag is initiated. Default=3;
15870 * @property clickPixelThresh
15874 clickPixelThresh: 3,
15877 * The number of milliseconds after the mousedown event to initiate the
15878 * drag if we don't get a mouseup event. Default=1000
15879 * @property clickTimeThresh
15883 clickTimeThresh: 350,
15886 * Flag that indicates that either the drag pixel threshold or the
15887 * mousdown time threshold has been met
15888 * @property dragThreshMet
15893 dragThreshMet: false,
15896 * Timeout used for the click time threshold
15897 * @property clickTimeout
15902 clickTimeout: null,
15905 * The X position of the mousedown event stored for later use when a
15906 * drag threshold is met.
15915 * The Y position of the mousedown event stored for later use when a
15916 * drag threshold is met.
15925 * Each DragDrop instance must be registered with the DragDropMgr.
15926 * This is executed in DragDrop.init()
15927 * @method regDragDrop
15928 * @param {DragDrop} oDD the DragDrop object to register
15929 * @param {String} sGroup the name of the group this element belongs to
15932 regDragDrop: function(oDD, sGroup) {
15933 if (!this.initialized) { this.init(); }
15935 if (!this.ids[sGroup]) {
15936 this.ids[sGroup] = {};
15938 this.ids[sGroup][oDD.id] = oDD;
15942 * Removes the supplied dd instance from the supplied group. Executed
15943 * by DragDrop.removeFromGroup, so don't call this function directly.
15944 * @method removeDDFromGroup
15948 removeDDFromGroup: function(oDD, sGroup) {
15949 if (!this.ids[sGroup]) {
15950 this.ids[sGroup] = {};
15953 var obj = this.ids[sGroup];
15954 if (obj && obj[oDD.id]) {
15955 delete obj[oDD.id];
15960 * Unregisters a drag and drop item. This is executed in
15961 * DragDrop.unreg, use that method instead of calling this directly.
15966 _remove: function(oDD) {
15967 for (var g in oDD.groups) {
15968 if (g && this.ids[g][oDD.id]) {
15969 delete this.ids[g][oDD.id];
15972 delete this.handleIds[oDD.id];
15976 * Each DragDrop handle element must be registered. This is done
15977 * automatically when executing DragDrop.setHandleElId()
15978 * @method regHandle
15979 * @param {String} sDDId the DragDrop id this element is a handle for
15980 * @param {String} sHandleId the id of the element that is the drag
15984 regHandle: function(sDDId, sHandleId) {
15985 if (!this.handleIds[sDDId]) {
15986 this.handleIds[sDDId] = {};
15988 this.handleIds[sDDId][sHandleId] = sHandleId;
15992 * Utility function to determine if a given element has been
15993 * registered as a drag drop item.
15994 * @method isDragDrop
15995 * @param {String} id the element id to check
15996 * @return {boolean} true if this element is a DragDrop item,
16000 isDragDrop: function(id) {
16001 return ( this.getDDById(id) ) ? true : false;
16005 * Returns the drag and drop instances that are in all groups the
16006 * passed in instance belongs to.
16007 * @method getRelated
16008 * @param {DragDrop} p_oDD the obj to get related data for
16009 * @param {boolean} bTargetsOnly if true, only return targetable objs
16010 * @return {DragDrop[]} the related instances
16013 getRelated: function(p_oDD, bTargetsOnly) {
16015 for (var i in p_oDD.groups) {
16016 for (j in this.ids[i]) {
16017 var dd = this.ids[i][j];
16018 if (! this.isTypeOfDD(dd)) {
16021 if (!bTargetsOnly || dd.isTarget) {
16022 oDDs[oDDs.length] = dd;
16031 * Returns true if the specified dd target is a legal target for
16032 * the specifice drag obj
16033 * @method isLegalTarget
16034 * @param {DragDrop} the drag obj
16035 * @param {DragDrop} the target
16036 * @return {boolean} true if the target is a legal target for the
16040 isLegalTarget: function (oDD, oTargetDD) {
16041 var targets = this.getRelated(oDD, true);
16042 for (var i=0, len=targets.length;i<len;++i) {
16043 if (targets[i].id == oTargetDD.id) {
16052 * My goal is to be able to transparently determine if an object is
16053 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16054 * returns "object", oDD.constructor.toString() always returns
16055 * "DragDrop" and not the name of the subclass. So for now it just
16056 * evaluates a well-known variable in DragDrop.
16057 * @method isTypeOfDD
16058 * @param {Object} the object to evaluate
16059 * @return {boolean} true if typeof oDD = DragDrop
16062 isTypeOfDD: function (oDD) {
16063 return (oDD && oDD.__ygDragDrop);
16067 * Utility function to determine if a given element has been
16068 * registered as a drag drop handle for the given Drag Drop object.
16070 * @param {String} id the element id to check
16071 * @return {boolean} true if this element is a DragDrop handle, false
16075 isHandle: function(sDDId, sHandleId) {
16076 return ( this.handleIds[sDDId] &&
16077 this.handleIds[sDDId][sHandleId] );
16081 * Returns the DragDrop instance for a given id
16082 * @method getDDById
16083 * @param {String} id the id of the DragDrop object
16084 * @return {DragDrop} the drag drop object, null if it is not found
16087 getDDById: function(id) {
16088 for (var i in this.ids) {
16089 if (this.ids[i][id]) {
16090 return this.ids[i][id];
16097 * Fired after a registered DragDrop object gets the mousedown event.
16098 * Sets up the events required to track the object being dragged
16099 * @method handleMouseDown
16100 * @param {Event} e the event
16101 * @param oDD the DragDrop object being dragged
16105 handleMouseDown: function(e, oDD) {
16107 Roo.QuickTips.disable();
16109 this.currentTarget = e.getTarget();
16111 this.dragCurrent = oDD;
16113 var el = oDD.getEl();
16115 // track start position
16116 this.startX = e.getPageX();
16117 this.startY = e.getPageY();
16119 this.deltaX = this.startX - el.offsetLeft;
16120 this.deltaY = this.startY - el.offsetTop;
16122 this.dragThreshMet = false;
16124 this.clickTimeout = setTimeout(
16126 var DDM = Roo.dd.DDM;
16127 DDM.startDrag(DDM.startX, DDM.startY);
16129 this.clickTimeThresh );
16133 * Fired when either the drag pixel threshol or the mousedown hold
16134 * time threshold has been met.
16135 * @method startDrag
16136 * @param x {int} the X position of the original mousedown
16137 * @param y {int} the Y position of the original mousedown
16140 startDrag: function(x, y) {
16141 clearTimeout(this.clickTimeout);
16142 if (this.dragCurrent) {
16143 this.dragCurrent.b4StartDrag(x, y);
16144 this.dragCurrent.startDrag(x, y);
16146 this.dragThreshMet = true;
16150 * Internal function to handle the mouseup event. Will be invoked
16151 * from the context of the document.
16152 * @method handleMouseUp
16153 * @param {Event} e the event
16157 handleMouseUp: function(e) {
16160 Roo.QuickTips.enable();
16162 if (! this.dragCurrent) {
16166 clearTimeout(this.clickTimeout);
16168 if (this.dragThreshMet) {
16169 this.fireEvents(e, true);
16179 * Utility to stop event propagation and event default, if these
16180 * features are turned on.
16181 * @method stopEvent
16182 * @param {Event} e the event as returned by this.getEvent()
16185 stopEvent: function(e){
16186 if(this.stopPropagation) {
16187 e.stopPropagation();
16190 if (this.preventDefault) {
16191 e.preventDefault();
16196 * Internal function to clean up event handlers after the drag
16197 * operation is complete
16199 * @param {Event} e the event
16203 stopDrag: function(e) {
16204 // Fire the drag end event for the item that was dragged
16205 if (this.dragCurrent) {
16206 if (this.dragThreshMet) {
16207 this.dragCurrent.b4EndDrag(e);
16208 this.dragCurrent.endDrag(e);
16211 this.dragCurrent.onMouseUp(e);
16214 this.dragCurrent = null;
16215 this.dragOvers = {};
16219 * Internal function to handle the mousemove event. Will be invoked
16220 * from the context of the html element.
16222 * @TODO figure out what we can do about mouse events lost when the
16223 * user drags objects beyond the window boundary. Currently we can
16224 * detect this in internet explorer by verifying that the mouse is
16225 * down during the mousemove event. Firefox doesn't give us the
16226 * button state on the mousemove event.
16227 * @method handleMouseMove
16228 * @param {Event} e the event
16232 handleMouseMove: function(e) {
16233 if (! this.dragCurrent) {
16237 // var button = e.which || e.button;
16239 // check for IE mouseup outside of page boundary
16240 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16242 return this.handleMouseUp(e);
16245 if (!this.dragThreshMet) {
16246 var diffX = Math.abs(this.startX - e.getPageX());
16247 var diffY = Math.abs(this.startY - e.getPageY());
16248 if (diffX > this.clickPixelThresh ||
16249 diffY > this.clickPixelThresh) {
16250 this.startDrag(this.startX, this.startY);
16254 if (this.dragThreshMet) {
16255 this.dragCurrent.b4Drag(e);
16256 this.dragCurrent.onDrag(e);
16257 if(!this.dragCurrent.moveOnly){
16258 this.fireEvents(e, false);
16268 * Iterates over all of the DragDrop elements to find ones we are
16269 * hovering over or dropping on
16270 * @method fireEvents
16271 * @param {Event} e the event
16272 * @param {boolean} isDrop is this a drop op or a mouseover op?
16276 fireEvents: function(e, isDrop) {
16277 var dc = this.dragCurrent;
16279 // If the user did the mouse up outside of the window, we could
16280 // get here even though we have ended the drag.
16281 if (!dc || dc.isLocked()) {
16285 var pt = e.getPoint();
16287 // cache the previous dragOver array
16293 var enterEvts = [];
16295 // Check to see if the object(s) we were hovering over is no longer
16296 // being hovered over so we can fire the onDragOut event
16297 for (var i in this.dragOvers) {
16299 var ddo = this.dragOvers[i];
16301 if (! this.isTypeOfDD(ddo)) {
16305 if (! this.isOverTarget(pt, ddo, this.mode)) {
16306 outEvts.push( ddo );
16309 oldOvers[i] = true;
16310 delete this.dragOvers[i];
16313 for (var sGroup in dc.groups) {
16315 if ("string" != typeof sGroup) {
16319 for (i in this.ids[sGroup]) {
16320 var oDD = this.ids[sGroup][i];
16321 if (! this.isTypeOfDD(oDD)) {
16325 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16326 if (this.isOverTarget(pt, oDD, this.mode)) {
16327 // look for drop interactions
16329 dropEvts.push( oDD );
16330 // look for drag enter and drag over interactions
16333 // initial drag over: dragEnter fires
16334 if (!oldOvers[oDD.id]) {
16335 enterEvts.push( oDD );
16336 // subsequent drag overs: dragOver fires
16338 overEvts.push( oDD );
16341 this.dragOvers[oDD.id] = oDD;
16349 if (outEvts.length) {
16350 dc.b4DragOut(e, outEvts);
16351 dc.onDragOut(e, outEvts);
16354 if (enterEvts.length) {
16355 dc.onDragEnter(e, enterEvts);
16358 if (overEvts.length) {
16359 dc.b4DragOver(e, overEvts);
16360 dc.onDragOver(e, overEvts);
16363 if (dropEvts.length) {
16364 dc.b4DragDrop(e, dropEvts);
16365 dc.onDragDrop(e, dropEvts);
16369 // fire dragout events
16371 for (i=0, len=outEvts.length; i<len; ++i) {
16372 dc.b4DragOut(e, outEvts[i].id);
16373 dc.onDragOut(e, outEvts[i].id);
16376 // fire enter events
16377 for (i=0,len=enterEvts.length; i<len; ++i) {
16378 // dc.b4DragEnter(e, oDD.id);
16379 dc.onDragEnter(e, enterEvts[i].id);
16382 // fire over events
16383 for (i=0,len=overEvts.length; i<len; ++i) {
16384 dc.b4DragOver(e, overEvts[i].id);
16385 dc.onDragOver(e, overEvts[i].id);
16388 // fire drop events
16389 for (i=0, len=dropEvts.length; i<len; ++i) {
16390 dc.b4DragDrop(e, dropEvts[i].id);
16391 dc.onDragDrop(e, dropEvts[i].id);
16396 // notify about a drop that did not find a target
16397 if (isDrop && !dropEvts.length) {
16398 dc.onInvalidDrop(e);
16404 * Helper function for getting the best match from the list of drag
16405 * and drop objects returned by the drag and drop events when we are
16406 * in INTERSECT mode. It returns either the first object that the
16407 * cursor is over, or the object that has the greatest overlap with
16408 * the dragged element.
16409 * @method getBestMatch
16410 * @param {DragDrop[]} dds The array of drag and drop objects
16412 * @return {DragDrop} The best single match
16415 getBestMatch: function(dds) {
16417 // Return null if the input is not what we expect
16418 //if (!dds || !dds.length || dds.length == 0) {
16420 // If there is only one item, it wins
16421 //} else if (dds.length == 1) {
16423 var len = dds.length;
16428 // Loop through the targeted items
16429 for (var i=0; i<len; ++i) {
16431 // If the cursor is over the object, it wins. If the
16432 // cursor is over multiple matches, the first one we come
16434 if (dd.cursorIsOver) {
16437 // Otherwise the object with the most overlap wins
16440 winner.overlap.getArea() < dd.overlap.getArea()) {
16451 * Refreshes the cache of the top-left and bottom-right points of the
16452 * drag and drop objects in the specified group(s). This is in the
16453 * format that is stored in the drag and drop instance, so typical
16456 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16460 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16462 * @TODO this really should be an indexed array. Alternatively this
16463 * method could accept both.
16464 * @method refreshCache
16465 * @param {Object} groups an associative array of groups to refresh
16468 refreshCache: function(groups) {
16469 for (var sGroup in groups) {
16470 if ("string" != typeof sGroup) {
16473 for (var i in this.ids[sGroup]) {
16474 var oDD = this.ids[sGroup][i];
16476 if (this.isTypeOfDD(oDD)) {
16477 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16478 var loc = this.getLocation(oDD);
16480 this.locationCache[oDD.id] = loc;
16482 delete this.locationCache[oDD.id];
16483 // this will unregister the drag and drop object if
16484 // the element is not in a usable state
16493 * This checks to make sure an element exists and is in the DOM. The
16494 * main purpose is to handle cases where innerHTML is used to remove
16495 * drag and drop objects from the DOM. IE provides an 'unspecified
16496 * error' when trying to access the offsetParent of such an element
16498 * @param {HTMLElement} el the element to check
16499 * @return {boolean} true if the element looks usable
16502 verifyEl: function(el) {
16507 parent = el.offsetParent;
16510 parent = el.offsetParent;
16521 * Returns a Region object containing the drag and drop element's position
16522 * and size, including the padding configured for it
16523 * @method getLocation
16524 * @param {DragDrop} oDD the drag and drop object to get the
16526 * @return {Roo.lib.Region} a Region object representing the total area
16527 * the element occupies, including any padding
16528 * the instance is configured for.
16531 getLocation: function(oDD) {
16532 if (! this.isTypeOfDD(oDD)) {
16536 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16539 pos= Roo.lib.Dom.getXY(el);
16547 x2 = x1 + el.offsetWidth;
16549 y2 = y1 + el.offsetHeight;
16551 t = y1 - oDD.padding[0];
16552 r = x2 + oDD.padding[1];
16553 b = y2 + oDD.padding[2];
16554 l = x1 - oDD.padding[3];
16556 return new Roo.lib.Region( t, r, b, l );
16560 * Checks the cursor location to see if it over the target
16561 * @method isOverTarget
16562 * @param {Roo.lib.Point} pt The point to evaluate
16563 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16564 * @return {boolean} true if the mouse is over the target
16568 isOverTarget: function(pt, oTarget, intersect) {
16569 // use cache if available
16570 var loc = this.locationCache[oTarget.id];
16571 if (!loc || !this.useCache) {
16572 loc = this.getLocation(oTarget);
16573 this.locationCache[oTarget.id] = loc;
16581 oTarget.cursorIsOver = loc.contains( pt );
16583 // DragDrop is using this as a sanity check for the initial mousedown
16584 // in this case we are done. In POINT mode, if the drag obj has no
16585 // contraints, we are also done. Otherwise we need to evaluate the
16586 // location of the target as related to the actual location of the
16587 // dragged element.
16588 var dc = this.dragCurrent;
16589 if (!dc || !dc.getTargetCoord ||
16590 (!intersect && !dc.constrainX && !dc.constrainY)) {
16591 return oTarget.cursorIsOver;
16594 oTarget.overlap = null;
16596 // Get the current location of the drag element, this is the
16597 // location of the mouse event less the delta that represents
16598 // where the original mousedown happened on the element. We
16599 // need to consider constraints and ticks as well.
16600 var pos = dc.getTargetCoord(pt.x, pt.y);
16602 var el = dc.getDragEl();
16603 var curRegion = new Roo.lib.Region( pos.y,
16604 pos.x + el.offsetWidth,
16605 pos.y + el.offsetHeight,
16608 var overlap = curRegion.intersect(loc);
16611 oTarget.overlap = overlap;
16612 return (intersect) ? true : oTarget.cursorIsOver;
16619 * unload event handler
16620 * @method _onUnload
16624 _onUnload: function(e, me) {
16625 Roo.dd.DragDropMgr.unregAll();
16629 * Cleans up the drag and drop events and objects.
16634 unregAll: function() {
16636 if (this.dragCurrent) {
16638 this.dragCurrent = null;
16641 this._execOnAll("unreg", []);
16643 for (i in this.elementCache) {
16644 delete this.elementCache[i];
16647 this.elementCache = {};
16652 * A cache of DOM elements
16653 * @property elementCache
16660 * Get the wrapper for the DOM element specified
16661 * @method getElWrapper
16662 * @param {String} id the id of the element to get
16663 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16665 * @deprecated This wrapper isn't that useful
16668 getElWrapper: function(id) {
16669 var oWrapper = this.elementCache[id];
16670 if (!oWrapper || !oWrapper.el) {
16671 oWrapper = this.elementCache[id] =
16672 new this.ElementWrapper(Roo.getDom(id));
16678 * Returns the actual DOM element
16679 * @method getElement
16680 * @param {String} id the id of the elment to get
16681 * @return {Object} The element
16682 * @deprecated use Roo.getDom instead
16685 getElement: function(id) {
16686 return Roo.getDom(id);
16690 * Returns the style property for the DOM element (i.e.,
16691 * document.getElById(id).style)
16693 * @param {String} id the id of the elment to get
16694 * @return {Object} The style property of the element
16695 * @deprecated use Roo.getDom instead
16698 getCss: function(id) {
16699 var el = Roo.getDom(id);
16700 return (el) ? el.style : null;
16704 * Inner class for cached elements
16705 * @class DragDropMgr.ElementWrapper
16710 ElementWrapper: function(el) {
16715 this.el = el || null;
16720 this.id = this.el && el.id;
16722 * A reference to the style property
16725 this.css = this.el && el.style;
16729 * Returns the X position of an html element
16731 * @param el the element for which to get the position
16732 * @return {int} the X coordinate
16734 * @deprecated use Roo.lib.Dom.getX instead
16737 getPosX: function(el) {
16738 return Roo.lib.Dom.getX(el);
16742 * Returns the Y position of an html element
16744 * @param el the element for which to get the position
16745 * @return {int} the Y coordinate
16746 * @deprecated use Roo.lib.Dom.getY instead
16749 getPosY: function(el) {
16750 return Roo.lib.Dom.getY(el);
16754 * Swap two nodes. In IE, we use the native method, for others we
16755 * emulate the IE behavior
16757 * @param n1 the first node to swap
16758 * @param n2 the other node to swap
16761 swapNode: function(n1, n2) {
16765 var p = n2.parentNode;
16766 var s = n2.nextSibling;
16769 p.insertBefore(n1, n2);
16770 } else if (n2 == n1.nextSibling) {
16771 p.insertBefore(n2, n1);
16773 n1.parentNode.replaceChild(n2, n1);
16774 p.insertBefore(n1, s);
16780 * Returns the current scroll position
16781 * @method getScroll
16785 getScroll: function () {
16786 var t, l, dde=document.documentElement, db=document.body;
16787 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16789 l = dde.scrollLeft;
16796 return { top: t, left: l };
16800 * Returns the specified element style property
16802 * @param {HTMLElement} el the element
16803 * @param {string} styleProp the style property
16804 * @return {string} The value of the style property
16805 * @deprecated use Roo.lib.Dom.getStyle
16808 getStyle: function(el, styleProp) {
16809 return Roo.fly(el).getStyle(styleProp);
16813 * Gets the scrollTop
16814 * @method getScrollTop
16815 * @return {int} the document's scrollTop
16818 getScrollTop: function () { return this.getScroll().top; },
16821 * Gets the scrollLeft
16822 * @method getScrollLeft
16823 * @return {int} the document's scrollTop
16826 getScrollLeft: function () { return this.getScroll().left; },
16829 * Sets the x/y position of an element to the location of the
16832 * @param {HTMLElement} moveEl The element to move
16833 * @param {HTMLElement} targetEl The position reference element
16836 moveToEl: function (moveEl, targetEl) {
16837 var aCoord = Roo.lib.Dom.getXY(targetEl);
16838 Roo.lib.Dom.setXY(moveEl, aCoord);
16842 * Numeric array sort function
16843 * @method numericSort
16846 numericSort: function(a, b) { return (a - b); },
16850 * @property _timeoutCount
16857 * Trying to make the load order less important. Without this we get
16858 * an error if this file is loaded before the Event Utility.
16859 * @method _addListeners
16863 _addListeners: function() {
16864 var DDM = Roo.dd.DDM;
16865 if ( Roo.lib.Event && document ) {
16868 if (DDM._timeoutCount > 2000) {
16870 setTimeout(DDM._addListeners, 10);
16871 if (document && document.body) {
16872 DDM._timeoutCount += 1;
16879 * Recursively searches the immediate parent and all child nodes for
16880 * the handle element in order to determine wheter or not it was
16882 * @method handleWasClicked
16883 * @param node the html element to inspect
16886 handleWasClicked: function(node, id) {
16887 if (this.isHandle(id, node.id)) {
16890 // check to see if this is a text node child of the one we want
16891 var p = node.parentNode;
16894 if (this.isHandle(id, p.id)) {
16909 // shorter alias, save a few bytes
16910 Roo.dd.DDM = Roo.dd.DragDropMgr;
16911 Roo.dd.DDM._addListeners();
16915 * Ext JS Library 1.1.1
16916 * Copyright(c) 2006-2007, Ext JS, LLC.
16918 * Originally Released Under LGPL - original licence link has changed is not relivant.
16921 * <script type="text/javascript">
16926 * A DragDrop implementation where the linked element follows the
16927 * mouse cursor during a drag.
16928 * @extends Roo.dd.DragDrop
16930 * @param {String} id the id of the linked element
16931 * @param {String} sGroup the group of related DragDrop items
16932 * @param {object} config an object containing configurable attributes
16933 * Valid properties for DD:
16936 Roo.dd.DD = function(id, sGroup, config) {
16938 this.init(id, sGroup, config);
16942 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16945 * When set to true, the utility automatically tries to scroll the browser
16946 * window wehn a drag and drop element is dragged near the viewport boundary.
16947 * Defaults to true.
16954 * Sets the pointer offset to the distance between the linked element's top
16955 * left corner and the location the element was clicked
16956 * @method autoOffset
16957 * @param {int} iPageX the X coordinate of the click
16958 * @param {int} iPageY the Y coordinate of the click
16960 autoOffset: function(iPageX, iPageY) {
16961 var x = iPageX - this.startPageX;
16962 var y = iPageY - this.startPageY;
16963 this.setDelta(x, y);
16967 * Sets the pointer offset. You can call this directly to force the
16968 * offset to be in a particular location (e.g., pass in 0,0 to set it
16969 * to the center of the object)
16971 * @param {int} iDeltaX the distance from the left
16972 * @param {int} iDeltaY the distance from the top
16974 setDelta: function(iDeltaX, iDeltaY) {
16975 this.deltaX = iDeltaX;
16976 this.deltaY = iDeltaY;
16980 * Sets the drag element to the location of the mousedown or click event,
16981 * maintaining the cursor location relative to the location on the element
16982 * that was clicked. Override this if you want to place the element in a
16983 * location other than where the cursor is.
16984 * @method setDragElPos
16985 * @param {int} iPageX the X coordinate of the mousedown or drag event
16986 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16988 setDragElPos: function(iPageX, iPageY) {
16989 // the first time we do this, we are going to check to make sure
16990 // the element has css positioning
16992 var el = this.getDragEl();
16993 this.alignElWithMouse(el, iPageX, iPageY);
16997 * Sets the element to the location of the mousedown or click event,
16998 * maintaining the cursor location relative to the location on the element
16999 * that was clicked. Override this if you want to place the element in a
17000 * location other than where the cursor is.
17001 * @method alignElWithMouse
17002 * @param {HTMLElement} el the element to move
17003 * @param {int} iPageX the X coordinate of the mousedown or drag event
17004 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17006 alignElWithMouse: function(el, iPageX, iPageY) {
17007 var oCoord = this.getTargetCoord(iPageX, iPageY);
17008 var fly = el.dom ? el : Roo.fly(el);
17009 if (!this.deltaSetXY) {
17010 var aCoord = [oCoord.x, oCoord.y];
17012 var newLeft = fly.getLeft(true);
17013 var newTop = fly.getTop(true);
17014 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17016 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17019 this.cachePosition(oCoord.x, oCoord.y);
17020 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17025 * Saves the most recent position so that we can reset the constraints and
17026 * tick marks on-demand. We need to know this so that we can calculate the
17027 * number of pixels the element is offset from its original position.
17028 * @method cachePosition
17029 * @param iPageX the current x position (optional, this just makes it so we
17030 * don't have to look it up again)
17031 * @param iPageY the current y position (optional, this just makes it so we
17032 * don't have to look it up again)
17034 cachePosition: function(iPageX, iPageY) {
17036 this.lastPageX = iPageX;
17037 this.lastPageY = iPageY;
17039 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17040 this.lastPageX = aCoord[0];
17041 this.lastPageY = aCoord[1];
17046 * Auto-scroll the window if the dragged object has been moved beyond the
17047 * visible window boundary.
17048 * @method autoScroll
17049 * @param {int} x the drag element's x position
17050 * @param {int} y the drag element's y position
17051 * @param {int} h the height of the drag element
17052 * @param {int} w the width of the drag element
17055 autoScroll: function(x, y, h, w) {
17058 // The client height
17059 var clientH = Roo.lib.Dom.getViewWidth();
17061 // The client width
17062 var clientW = Roo.lib.Dom.getViewHeight();
17064 // The amt scrolled down
17065 var st = this.DDM.getScrollTop();
17067 // The amt scrolled right
17068 var sl = this.DDM.getScrollLeft();
17070 // Location of the bottom of the element
17073 // Location of the right of the element
17076 // The distance from the cursor to the bottom of the visible area,
17077 // adjusted so that we don't scroll if the cursor is beyond the
17078 // element drag constraints
17079 var toBot = (clientH + st - y - this.deltaY);
17081 // The distance from the cursor to the right of the visible area
17082 var toRight = (clientW + sl - x - this.deltaX);
17085 // How close to the edge the cursor must be before we scroll
17086 // var thresh = (document.all) ? 100 : 40;
17089 // How many pixels to scroll per autoscroll op. This helps to reduce
17090 // clunky scrolling. IE is more sensitive about this ... it needs this
17091 // value to be higher.
17092 var scrAmt = (document.all) ? 80 : 30;
17094 // Scroll down if we are near the bottom of the visible page and the
17095 // obj extends below the crease
17096 if ( bot > clientH && toBot < thresh ) {
17097 window.scrollTo(sl, st + scrAmt);
17100 // Scroll up if the window is scrolled down and the top of the object
17101 // goes above the top border
17102 if ( y < st && st > 0 && y - st < thresh ) {
17103 window.scrollTo(sl, st - scrAmt);
17106 // Scroll right if the obj is beyond the right border and the cursor is
17107 // near the border.
17108 if ( right > clientW && toRight < thresh ) {
17109 window.scrollTo(sl + scrAmt, st);
17112 // Scroll left if the window has been scrolled to the right and the obj
17113 // extends past the left border
17114 if ( x < sl && sl > 0 && x - sl < thresh ) {
17115 window.scrollTo(sl - scrAmt, st);
17121 * Finds the location the element should be placed if we want to move
17122 * it to where the mouse location less the click offset would place us.
17123 * @method getTargetCoord
17124 * @param {int} iPageX the X coordinate of the click
17125 * @param {int} iPageY the Y coordinate of the click
17126 * @return an object that contains the coordinates (Object.x and Object.y)
17129 getTargetCoord: function(iPageX, iPageY) {
17132 var x = iPageX - this.deltaX;
17133 var y = iPageY - this.deltaY;
17135 if (this.constrainX) {
17136 if (x < this.minX) { x = this.minX; }
17137 if (x > this.maxX) { x = this.maxX; }
17140 if (this.constrainY) {
17141 if (y < this.minY) { y = this.minY; }
17142 if (y > this.maxY) { y = this.maxY; }
17145 x = this.getTick(x, this.xTicks);
17146 y = this.getTick(y, this.yTicks);
17153 * Sets up config options specific to this class. Overrides
17154 * Roo.dd.DragDrop, but all versions of this method through the
17155 * inheritance chain are called
17157 applyConfig: function() {
17158 Roo.dd.DD.superclass.applyConfig.call(this);
17159 this.scroll = (this.config.scroll !== false);
17163 * Event that fires prior to the onMouseDown event. Overrides
17166 b4MouseDown: function(e) {
17167 // this.resetConstraints();
17168 this.autoOffset(e.getPageX(),
17173 * Event that fires prior to the onDrag event. Overrides
17176 b4Drag: function(e) {
17177 this.setDragElPos(e.getPageX(),
17181 toString: function() {
17182 return ("DD " + this.id);
17185 //////////////////////////////////////////////////////////////////////////
17186 // Debugging ygDragDrop events that can be overridden
17187 //////////////////////////////////////////////////////////////////////////
17189 startDrag: function(x, y) {
17192 onDrag: function(e) {
17195 onDragEnter: function(e, id) {
17198 onDragOver: function(e, id) {
17201 onDragOut: function(e, id) {
17204 onDragDrop: function(e, id) {
17207 endDrag: function(e) {
17214 * Ext JS Library 1.1.1
17215 * Copyright(c) 2006-2007, Ext JS, LLC.
17217 * Originally Released Under LGPL - original licence link has changed is not relivant.
17220 * <script type="text/javascript">
17224 * @class Roo.dd.DDProxy
17225 * A DragDrop implementation that inserts an empty, bordered div into
17226 * the document that follows the cursor during drag operations. At the time of
17227 * the click, the frame div is resized to the dimensions of the linked html
17228 * element, and moved to the exact location of the linked element.
17230 * References to the "frame" element refer to the single proxy element that
17231 * was created to be dragged in place of all DDProxy elements on the
17234 * @extends Roo.dd.DD
17236 * @param {String} id the id of the linked html element
17237 * @param {String} sGroup the group of related DragDrop objects
17238 * @param {object} config an object containing configurable attributes
17239 * Valid properties for DDProxy in addition to those in DragDrop:
17240 * resizeFrame, centerFrame, dragElId
17242 Roo.dd.DDProxy = function(id, sGroup, config) {
17244 this.init(id, sGroup, config);
17250 * The default drag frame div id
17251 * @property Roo.dd.DDProxy.dragElId
17255 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17257 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17260 * By default we resize the drag frame to be the same size as the element
17261 * we want to drag (this is to get the frame effect). We can turn it off
17262 * if we want a different behavior.
17263 * @property resizeFrame
17269 * By default the frame is positioned exactly where the drag element is, so
17270 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17271 * you do not have constraints on the obj is to have the drag frame centered
17272 * around the cursor. Set centerFrame to true for this effect.
17273 * @property centerFrame
17276 centerFrame: false,
17279 * Creates the proxy element if it does not yet exist
17280 * @method createFrame
17282 createFrame: function() {
17284 var body = document.body;
17286 if (!body || !body.firstChild) {
17287 setTimeout( function() { self.createFrame(); }, 50 );
17291 var div = this.getDragEl();
17294 div = document.createElement("div");
17295 div.id = this.dragElId;
17298 s.position = "absolute";
17299 s.visibility = "hidden";
17301 s.border = "2px solid #aaa";
17304 // appendChild can blow up IE if invoked prior to the window load event
17305 // while rendering a table. It is possible there are other scenarios
17306 // that would cause this to happen as well.
17307 body.insertBefore(div, body.firstChild);
17312 * Initialization for the drag frame element. Must be called in the
17313 * constructor of all subclasses
17314 * @method initFrame
17316 initFrame: function() {
17317 this.createFrame();
17320 applyConfig: function() {
17321 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17323 this.resizeFrame = (this.config.resizeFrame !== false);
17324 this.centerFrame = (this.config.centerFrame);
17325 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17329 * Resizes the drag frame to the dimensions of the clicked object, positions
17330 * it over the object, and finally displays it
17331 * @method showFrame
17332 * @param {int} iPageX X click position
17333 * @param {int} iPageY Y click position
17336 showFrame: function(iPageX, iPageY) {
17337 var el = this.getEl();
17338 var dragEl = this.getDragEl();
17339 var s = dragEl.style;
17341 this._resizeProxy();
17343 if (this.centerFrame) {
17344 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17345 Math.round(parseInt(s.height, 10)/2) );
17348 this.setDragElPos(iPageX, iPageY);
17350 Roo.fly(dragEl).show();
17354 * The proxy is automatically resized to the dimensions of the linked
17355 * element when a drag is initiated, unless resizeFrame is set to false
17356 * @method _resizeProxy
17359 _resizeProxy: function() {
17360 if (this.resizeFrame) {
17361 var el = this.getEl();
17362 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17366 // overrides Roo.dd.DragDrop
17367 b4MouseDown: function(e) {
17368 var x = e.getPageX();
17369 var y = e.getPageY();
17370 this.autoOffset(x, y);
17371 this.setDragElPos(x, y);
17374 // overrides Roo.dd.DragDrop
17375 b4StartDrag: function(x, y) {
17376 // show the drag frame
17377 this.showFrame(x, y);
17380 // overrides Roo.dd.DragDrop
17381 b4EndDrag: function(e) {
17382 Roo.fly(this.getDragEl()).hide();
17385 // overrides Roo.dd.DragDrop
17386 // By default we try to move the element to the last location of the frame.
17387 // This is so that the default behavior mirrors that of Roo.dd.DD.
17388 endDrag: function(e) {
17390 var lel = this.getEl();
17391 var del = this.getDragEl();
17393 // Show the drag frame briefly so we can get its position
17394 del.style.visibility = "";
17397 // Hide the linked element before the move to get around a Safari
17399 lel.style.visibility = "hidden";
17400 Roo.dd.DDM.moveToEl(lel, del);
17401 del.style.visibility = "hidden";
17402 lel.style.visibility = "";
17407 beforeMove : function(){
17411 afterDrag : function(){
17415 toString: function() {
17416 return ("DDProxy " + this.id);
17422 * Ext JS Library 1.1.1
17423 * Copyright(c) 2006-2007, Ext JS, LLC.
17425 * Originally Released Under LGPL - original licence link has changed is not relivant.
17428 * <script type="text/javascript">
17432 * @class Roo.dd.DDTarget
17433 * A DragDrop implementation that does not move, but can be a drop
17434 * target. You would get the same result by simply omitting implementation
17435 * for the event callbacks, but this way we reduce the processing cost of the
17436 * event listener and the callbacks.
17437 * @extends Roo.dd.DragDrop
17439 * @param {String} id the id of the element that is a drop target
17440 * @param {String} sGroup the group of related DragDrop objects
17441 * @param {object} config an object containing configurable attributes
17442 * Valid properties for DDTarget in addition to those in
17446 Roo.dd.DDTarget = function(id, sGroup, config) {
17448 this.initTarget(id, sGroup, config);
17450 if (config.listeners || config.events) {
17451 Roo.dd.DragDrop.superclass.constructor.call(this, {
17452 listeners : config.listeners || {},
17453 events : config.events || {}
17458 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17459 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17460 toString: function() {
17461 return ("DDTarget " + this.id);
17466 * Ext JS Library 1.1.1
17467 * Copyright(c) 2006-2007, Ext JS, LLC.
17469 * Originally Released Under LGPL - original licence link has changed is not relivant.
17472 * <script type="text/javascript">
17477 * @class Roo.dd.ScrollManager
17478 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17479 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17482 Roo.dd.ScrollManager = function(){
17483 var ddm = Roo.dd.DragDropMgr;
17488 var onStop = function(e){
17493 var triggerRefresh = function(){
17494 if(ddm.dragCurrent){
17495 ddm.refreshCache(ddm.dragCurrent.groups);
17499 var doScroll = function(){
17500 if(ddm.dragCurrent){
17501 var dds = Roo.dd.ScrollManager;
17503 if(proc.el.scroll(proc.dir, dds.increment)){
17507 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17512 var clearProc = function(){
17514 clearInterval(proc.id);
17521 var startProc = function(el, dir){
17525 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17528 var onFire = function(e, isDrop){
17529 if(isDrop || !ddm.dragCurrent){ return; }
17530 var dds = Roo.dd.ScrollManager;
17531 if(!dragEl || dragEl != ddm.dragCurrent){
17532 dragEl = ddm.dragCurrent;
17533 // refresh regions on drag start
17534 dds.refreshCache();
17537 var xy = Roo.lib.Event.getXY(e);
17538 var pt = new Roo.lib.Point(xy[0], xy[1]);
17539 for(var id in els){
17540 var el = els[id], r = el._region;
17541 if(r && r.contains(pt) && el.isScrollable()){
17542 if(r.bottom - pt.y <= dds.thresh){
17544 startProc(el, "down");
17547 }else if(r.right - pt.x <= dds.thresh){
17549 startProc(el, "left");
17552 }else if(pt.y - r.top <= dds.thresh){
17554 startProc(el, "up");
17557 }else if(pt.x - r.left <= dds.thresh){
17559 startProc(el, "right");
17568 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17569 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17573 * Registers new overflow element(s) to auto scroll
17574 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17576 register : function(el){
17577 if(el instanceof Array){
17578 for(var i = 0, len = el.length; i < len; i++) {
17579 this.register(el[i]);
17588 * Unregisters overflow element(s) so they are no longer scrolled
17589 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17591 unregister : function(el){
17592 if(el instanceof Array){
17593 for(var i = 0, len = el.length; i < len; i++) {
17594 this.unregister(el[i]);
17603 * The number of pixels from the edge of a container the pointer needs to be to
17604 * trigger scrolling (defaults to 25)
17610 * The number of pixels to scroll in each scroll increment (defaults to 50)
17616 * The frequency of scrolls in milliseconds (defaults to 500)
17622 * True to animate the scroll (defaults to true)
17628 * The animation duration in seconds -
17629 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17635 * Manually trigger a cache refresh.
17637 refreshCache : function(){
17638 for(var id in els){
17639 if(typeof els[id] == 'object'){ // for people extending the object prototype
17640 els[id]._region = els[id].getRegion();
17647 * Ext JS Library 1.1.1
17648 * Copyright(c) 2006-2007, Ext JS, LLC.
17650 * Originally Released Under LGPL - original licence link has changed is not relivant.
17653 * <script type="text/javascript">
17658 * @class Roo.dd.Registry
17659 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17660 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17663 Roo.dd.Registry = function(){
17666 var autoIdSeed = 0;
17668 var getId = function(el, autogen){
17669 if(typeof el == "string"){
17673 if(!id && autogen !== false){
17674 id = "roodd-" + (++autoIdSeed);
17682 * Register a drag drop element
17683 * @param {String|HTMLElement} element The id or DOM node to register
17684 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17685 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17686 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17687 * populated in the data object (if applicable):
17689 Value Description<br />
17690 --------- ------------------------------------------<br />
17691 handles Array of DOM nodes that trigger dragging<br />
17692 for the element being registered<br />
17693 isHandle True if the element passed in triggers<br />
17694 dragging itself, else false
17697 register : function(el, data){
17699 if(typeof el == "string"){
17700 el = document.getElementById(el);
17703 elements[getId(el)] = data;
17704 if(data.isHandle !== false){
17705 handles[data.ddel.id] = data;
17708 var hs = data.handles;
17709 for(var i = 0, len = hs.length; i < len; i++){
17710 handles[getId(hs[i])] = data;
17716 * Unregister a drag drop element
17717 * @param {String|HTMLElement} element The id or DOM node to unregister
17719 unregister : function(el){
17720 var id = getId(el, false);
17721 var data = elements[id];
17723 delete elements[id];
17725 var hs = data.handles;
17726 for(var i = 0, len = hs.length; i < len; i++){
17727 delete handles[getId(hs[i], false)];
17734 * Returns the handle registered for a DOM Node by id
17735 * @param {String|HTMLElement} id The DOM node or id to look up
17736 * @return {Object} handle The custom handle data
17738 getHandle : function(id){
17739 if(typeof id != "string"){ // must be element?
17742 return handles[id];
17746 * Returns the handle that is registered for the DOM node that is the target of the event
17747 * @param {Event} e The event
17748 * @return {Object} handle The custom handle data
17750 getHandleFromEvent : function(e){
17751 var t = Roo.lib.Event.getTarget(e);
17752 return t ? handles[t.id] : null;
17756 * Returns a custom data object that is registered for a DOM node by id
17757 * @param {String|HTMLElement} id The DOM node or id to look up
17758 * @return {Object} data The custom data
17760 getTarget : function(id){
17761 if(typeof id != "string"){ // must be element?
17764 return elements[id];
17768 * Returns a custom data object that is registered for the DOM node that is the target of the event
17769 * @param {Event} e The event
17770 * @return {Object} data The custom data
17772 getTargetFromEvent : function(e){
17773 var t = Roo.lib.Event.getTarget(e);
17774 return t ? elements[t.id] || handles[t.id] : null;
17779 * Ext JS Library 1.1.1
17780 * Copyright(c) 2006-2007, Ext JS, LLC.
17782 * Originally Released Under LGPL - original licence link has changed is not relivant.
17785 * <script type="text/javascript">
17790 * @class Roo.dd.StatusProxy
17791 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17792 * default drag proxy used by all Roo.dd components.
17794 * @param {Object} config
17796 Roo.dd.StatusProxy = function(config){
17797 Roo.apply(this, config);
17798 this.id = this.id || Roo.id();
17799 this.el = new Roo.Layer({
17801 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17802 {tag: "div", cls: "x-dd-drop-icon"},
17803 {tag: "div", cls: "x-dd-drag-ghost"}
17806 shadow: !config || config.shadow !== false
17808 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17809 this.dropStatus = this.dropNotAllowed;
17812 Roo.dd.StatusProxy.prototype = {
17814 * @cfg {String} dropAllowed
17815 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17817 dropAllowed : "x-dd-drop-ok",
17819 * @cfg {String} dropNotAllowed
17820 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17822 dropNotAllowed : "x-dd-drop-nodrop",
17825 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17826 * over the current target element.
17827 * @param {String} cssClass The css class for the new drop status indicator image
17829 setStatus : function(cssClass){
17830 cssClass = cssClass || this.dropNotAllowed;
17831 if(this.dropStatus != cssClass){
17832 this.el.replaceClass(this.dropStatus, cssClass);
17833 this.dropStatus = cssClass;
17838 * Resets the status indicator to the default dropNotAllowed value
17839 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17841 reset : function(clearGhost){
17842 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17843 this.dropStatus = this.dropNotAllowed;
17845 this.ghost.update("");
17850 * Updates the contents of the ghost element
17851 * @param {String} html The html that will replace the current innerHTML of the ghost element
17853 update : function(html){
17854 if(typeof html == "string"){
17855 this.ghost.update(html);
17857 this.ghost.update("");
17858 html.style.margin = "0";
17859 this.ghost.dom.appendChild(html);
17861 // ensure float = none set?? cant remember why though.
17862 var el = this.ghost.dom.firstChild;
17864 Roo.fly(el).setStyle('float', 'none');
17869 * Returns the underlying proxy {@link Roo.Layer}
17870 * @return {Roo.Layer} el
17872 getEl : function(){
17877 * Returns the ghost element
17878 * @return {Roo.Element} el
17880 getGhost : function(){
17886 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17888 hide : function(clear){
17896 * Stops the repair animation if it's currently running
17899 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17905 * Displays this proxy
17912 * Force the Layer to sync its shadow and shim positions to the element
17919 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17920 * invalid drop operation by the item being dragged.
17921 * @param {Array} xy The XY position of the element ([x, y])
17922 * @param {Function} callback The function to call after the repair is complete
17923 * @param {Object} scope The scope in which to execute the callback
17925 repair : function(xy, callback, scope){
17926 this.callback = callback;
17927 this.scope = scope;
17928 if(xy && this.animRepair !== false){
17929 this.el.addClass("x-dd-drag-repair");
17930 this.el.hideUnders(true);
17931 this.anim = this.el.shift({
17932 duration: this.repairDuration || .5,
17936 callback: this.afterRepair,
17940 this.afterRepair();
17945 afterRepair : function(){
17947 if(typeof this.callback == "function"){
17948 this.callback.call(this.scope || this);
17950 this.callback = null;
17955 * Ext JS Library 1.1.1
17956 * Copyright(c) 2006-2007, Ext JS, LLC.
17958 * Originally Released Under LGPL - original licence link has changed is not relivant.
17961 * <script type="text/javascript">
17965 * @class Roo.dd.DragSource
17966 * @extends Roo.dd.DDProxy
17967 * A simple class that provides the basic implementation needed to make any element draggable.
17969 * @param {String/HTMLElement/Element} el The container element
17970 * @param {Object} config
17972 Roo.dd.DragSource = function(el, config){
17973 this.el = Roo.get(el);
17974 this.dragData = {};
17976 Roo.apply(this, config);
17979 this.proxy = new Roo.dd.StatusProxy();
17982 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17983 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17985 this.dragging = false;
17988 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17990 * @cfg {String} dropAllowed
17991 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17993 dropAllowed : "x-dd-drop-ok",
17995 * @cfg {String} dropNotAllowed
17996 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17998 dropNotAllowed : "x-dd-drop-nodrop",
18001 * Returns the data object associated with this drag source
18002 * @return {Object} data An object containing arbitrary data
18004 getDragData : function(e){
18005 return this.dragData;
18009 onDragEnter : function(e, id){
18010 var target = Roo.dd.DragDropMgr.getDDById(id);
18011 this.cachedTarget = target;
18012 if(this.beforeDragEnter(target, e, id) !== false){
18013 if(target.isNotifyTarget){
18014 var status = target.notifyEnter(this, e, this.dragData);
18015 this.proxy.setStatus(status);
18017 this.proxy.setStatus(this.dropAllowed);
18020 if(this.afterDragEnter){
18022 * An empty function by default, but provided so that you can perform a custom action
18023 * when the dragged item enters the drop target by providing an implementation.
18024 * @param {Roo.dd.DragDrop} target The drop target
18025 * @param {Event} e The event object
18026 * @param {String} id The id of the dragged element
18027 * @method afterDragEnter
18029 this.afterDragEnter(target, e, id);
18035 * An empty function by default, but provided so that you can perform a custom action
18036 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18037 * @param {Roo.dd.DragDrop} target The drop target
18038 * @param {Event} e The event object
18039 * @param {String} id The id of the dragged element
18040 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18042 beforeDragEnter : function(target, e, id){
18047 alignElWithMouse: function() {
18048 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18053 onDragOver : function(e, id){
18054 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18055 if(this.beforeDragOver(target, e, id) !== false){
18056 if(target.isNotifyTarget){
18057 var status = target.notifyOver(this, e, this.dragData);
18058 this.proxy.setStatus(status);
18061 if(this.afterDragOver){
18063 * An empty function by default, but provided so that you can perform a custom action
18064 * while the dragged item is over the drop target by providing an implementation.
18065 * @param {Roo.dd.DragDrop} target The drop target
18066 * @param {Event} e The event object
18067 * @param {String} id The id of the dragged element
18068 * @method afterDragOver
18070 this.afterDragOver(target, e, id);
18076 * An empty function by default, but provided so that you can perform a custom action
18077 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18078 * @param {Roo.dd.DragDrop} target The drop target
18079 * @param {Event} e The event object
18080 * @param {String} id The id of the dragged element
18081 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18083 beforeDragOver : function(target, e, id){
18088 onDragOut : function(e, id){
18089 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18090 if(this.beforeDragOut(target, e, id) !== false){
18091 if(target.isNotifyTarget){
18092 target.notifyOut(this, e, this.dragData);
18094 this.proxy.reset();
18095 if(this.afterDragOut){
18097 * An empty function by default, but provided so that you can perform a custom action
18098 * after the dragged item is dragged out of the target without dropping.
18099 * @param {Roo.dd.DragDrop} target The drop target
18100 * @param {Event} e The event object
18101 * @param {String} id The id of the dragged element
18102 * @method afterDragOut
18104 this.afterDragOut(target, e, id);
18107 this.cachedTarget = null;
18111 * An empty function by default, but provided so that you can perform a custom action before the dragged
18112 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18113 * @param {Roo.dd.DragDrop} target The drop target
18114 * @param {Event} e The event object
18115 * @param {String} id The id of the dragged element
18116 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18118 beforeDragOut : function(target, e, id){
18123 onDragDrop : function(e, id){
18124 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18125 if(this.beforeDragDrop(target, e, id) !== false){
18126 if(target.isNotifyTarget){
18127 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18128 this.onValidDrop(target, e, id);
18130 this.onInvalidDrop(target, e, id);
18133 this.onValidDrop(target, e, id);
18136 if(this.afterDragDrop){
18138 * An empty function by default, but provided so that you can perform a custom action
18139 * after a valid drag drop has occurred by providing an implementation.
18140 * @param {Roo.dd.DragDrop} target The drop target
18141 * @param {Event} e The event object
18142 * @param {String} id The id of the dropped element
18143 * @method afterDragDrop
18145 this.afterDragDrop(target, e, id);
18148 delete this.cachedTarget;
18152 * An empty function by default, but provided so that you can perform a custom action before the dragged
18153 * item is dropped onto the target and optionally cancel the onDragDrop.
18154 * @param {Roo.dd.DragDrop} target The drop target
18155 * @param {Event} e The event object
18156 * @param {String} id The id of the dragged element
18157 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18159 beforeDragDrop : function(target, e, id){
18164 onValidDrop : function(target, e, id){
18166 if(this.afterValidDrop){
18168 * An empty function by default, but provided so that you can perform a custom action
18169 * after a valid drop has occurred by providing an implementation.
18170 * @param {Object} target The target DD
18171 * @param {Event} e The event object
18172 * @param {String} id The id of the dropped element
18173 * @method afterInvalidDrop
18175 this.afterValidDrop(target, e, id);
18180 getRepairXY : function(e, data){
18181 return this.el.getXY();
18185 onInvalidDrop : function(target, e, id){
18186 this.beforeInvalidDrop(target, e, id);
18187 if(this.cachedTarget){
18188 if(this.cachedTarget.isNotifyTarget){
18189 this.cachedTarget.notifyOut(this, e, this.dragData);
18191 this.cacheTarget = null;
18193 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18195 if(this.afterInvalidDrop){
18197 * An empty function by default, but provided so that you can perform a custom action
18198 * after an invalid drop has occurred by providing an implementation.
18199 * @param {Event} e The event object
18200 * @param {String} id The id of the dropped element
18201 * @method afterInvalidDrop
18203 this.afterInvalidDrop(e, id);
18208 afterRepair : function(){
18210 this.el.highlight(this.hlColor || "c3daf9");
18212 this.dragging = false;
18216 * An empty function by default, but provided so that you can perform a custom action after an invalid
18217 * drop has occurred.
18218 * @param {Roo.dd.DragDrop} target The drop target
18219 * @param {Event} e The event object
18220 * @param {String} id The id of the dragged element
18221 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18223 beforeInvalidDrop : function(target, e, id){
18228 handleMouseDown : function(e){
18229 if(this.dragging) {
18232 var data = this.getDragData(e);
18233 if(data && this.onBeforeDrag(data, e) !== false){
18234 this.dragData = data;
18236 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18241 * An empty function by default, but provided so that you can perform a custom action before the initial
18242 * drag event begins and optionally cancel it.
18243 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18244 * @param {Event} e The event object
18245 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18247 onBeforeDrag : function(data, e){
18252 * An empty function by default, but provided so that you can perform a custom action once the initial
18253 * drag event has begun. The drag cannot be canceled from this function.
18254 * @param {Number} x The x position of the click on the dragged object
18255 * @param {Number} y The y position of the click on the dragged object
18257 onStartDrag : Roo.emptyFn,
18259 // private - YUI override
18260 startDrag : function(x, y){
18261 this.proxy.reset();
18262 this.dragging = true;
18263 this.proxy.update("");
18264 this.onInitDrag(x, y);
18269 onInitDrag : function(x, y){
18270 var clone = this.el.dom.cloneNode(true);
18271 clone.id = Roo.id(); // prevent duplicate ids
18272 this.proxy.update(clone);
18273 this.onStartDrag(x, y);
18278 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18279 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18281 getProxy : function(){
18286 * Hides the drag source's {@link Roo.dd.StatusProxy}
18288 hideProxy : function(){
18290 this.proxy.reset(true);
18291 this.dragging = false;
18295 triggerCacheRefresh : function(){
18296 Roo.dd.DDM.refreshCache(this.groups);
18299 // private - override to prevent hiding
18300 b4EndDrag: function(e) {
18303 // private - override to prevent moving
18304 endDrag : function(e){
18305 this.onEndDrag(this.dragData, e);
18309 onEndDrag : function(data, e){
18312 // private - pin to cursor
18313 autoOffset : function(x, y) {
18314 this.setDelta(-12, -20);
18318 * Ext JS Library 1.1.1
18319 * Copyright(c) 2006-2007, Ext JS, LLC.
18321 * Originally Released Under LGPL - original licence link has changed is not relivant.
18324 * <script type="text/javascript">
18329 * @class Roo.dd.DropTarget
18330 * @extends Roo.dd.DDTarget
18331 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18332 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18334 * @param {String/HTMLElement/Element} el The container element
18335 * @param {Object} config
18337 Roo.dd.DropTarget = function(el, config){
18338 this.el = Roo.get(el);
18340 var listeners = false; ;
18341 if (config && config.listeners) {
18342 listeners= config.listeners;
18343 delete config.listeners;
18345 Roo.apply(this, config);
18347 if(this.containerScroll){
18348 Roo.dd.ScrollManager.register(this.el);
18352 * @scope Roo.dd.DropTarget
18357 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18358 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18359 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18361 * IMPORTANT : it should set this.overClass and this.dropAllowed
18363 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18364 * @param {Event} e The event
18365 * @param {Object} data An object containing arbitrary data supplied by the drag source
18371 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18372 * This method will be called on every mouse movement while the drag source is over the drop target.
18373 * This default implementation simply returns the dropAllowed config value.
18375 * IMPORTANT : it should set this.dropAllowed
18377 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18378 * @param {Event} e The event
18379 * @param {Object} data An object containing arbitrary data supplied by the drag source
18385 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18386 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18387 * overClass (if any) from the drop element.
18388 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18389 * @param {Event} e The event
18390 * @param {Object} data An object containing arbitrary data supplied by the drag source
18396 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18397 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18398 * implementation that does something to process the drop event and returns true so that the drag source's
18399 * repair action does not run.
18401 * IMPORTANT : it should set this.success
18403 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18404 * @param {Event} e The event
18405 * @param {Object} data An object containing arbitrary data supplied by the drag source
18411 Roo.dd.DropTarget.superclass.constructor.call( this,
18413 this.ddGroup || this.group,
18416 listeners : listeners || {}
18424 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18426 * @cfg {String} overClass
18427 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18430 * @cfg {String} ddGroup
18431 * The drag drop group to handle drop events for
18435 * @cfg {String} dropAllowed
18436 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18438 dropAllowed : "x-dd-drop-ok",
18440 * @cfg {String} dropNotAllowed
18441 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18443 dropNotAllowed : "x-dd-drop-nodrop",
18445 * @cfg {boolean} success
18446 * set this after drop listener..
18450 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18451 * if the drop point is valid for over/enter..
18458 isNotifyTarget : true,
18463 notifyEnter : function(dd, e, data)
18466 this.fireEvent('enter', dd, e, data);
18467 if(this.overClass){
18468 this.el.addClass(this.overClass);
18470 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18471 this.valid ? this.dropAllowed : this.dropNotAllowed
18478 notifyOver : function(dd, e, data)
18481 this.fireEvent('over', dd, e, data);
18482 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18483 this.valid ? this.dropAllowed : this.dropNotAllowed
18490 notifyOut : function(dd, e, data)
18492 this.fireEvent('out', dd, e, data);
18493 if(this.overClass){
18494 this.el.removeClass(this.overClass);
18501 notifyDrop : function(dd, e, data)
18503 this.success = false;
18504 this.fireEvent('drop', dd, e, data);
18505 return this.success;
18509 * Ext JS Library 1.1.1
18510 * Copyright(c) 2006-2007, Ext JS, LLC.
18512 * Originally Released Under LGPL - original licence link has changed is not relivant.
18515 * <script type="text/javascript">
18520 * @class Roo.dd.DragZone
18521 * @extends Roo.dd.DragSource
18522 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18523 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18525 * @param {String/HTMLElement/Element} el The container element
18526 * @param {Object} config
18528 Roo.dd.DragZone = function(el, config){
18529 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18530 if(this.containerScroll){
18531 Roo.dd.ScrollManager.register(this.el);
18535 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18537 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18538 * for auto scrolling during drag operations.
18541 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18542 * method after a failed drop (defaults to "c3daf9" - light blue)
18546 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18547 * for a valid target to drag based on the mouse down. Override this method
18548 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18549 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18550 * @param {EventObject} e The mouse down event
18551 * @return {Object} The dragData
18553 getDragData : function(e){
18554 return Roo.dd.Registry.getHandleFromEvent(e);
18558 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18559 * this.dragData.ddel
18560 * @param {Number} x The x position of the click on the dragged object
18561 * @param {Number} y The y position of the click on the dragged object
18562 * @return {Boolean} true to continue the drag, false to cancel
18564 onInitDrag : function(x, y){
18565 this.proxy.update(this.dragData.ddel.cloneNode(true));
18566 this.onStartDrag(x, y);
18571 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18573 afterRepair : function(){
18575 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18577 this.dragging = false;
18581 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18582 * the XY of this.dragData.ddel
18583 * @param {EventObject} e The mouse up event
18584 * @return {Array} The xy location (e.g. [100, 200])
18586 getRepairXY : function(e){
18587 return Roo.Element.fly(this.dragData.ddel).getXY();
18591 * Ext JS Library 1.1.1
18592 * Copyright(c) 2006-2007, Ext JS, LLC.
18594 * Originally Released Under LGPL - original licence link has changed is not relivant.
18597 * <script type="text/javascript">
18600 * @class Roo.dd.DropZone
18601 * @extends Roo.dd.DropTarget
18602 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18603 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18605 * @param {String/HTMLElement/Element} el The container element
18606 * @param {Object} config
18608 Roo.dd.DropZone = function(el, config){
18609 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18612 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18614 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18615 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18616 * provide your own custom lookup.
18617 * @param {Event} e The event
18618 * @return {Object} data The custom data
18620 getTargetFromEvent : function(e){
18621 return Roo.dd.Registry.getTargetFromEvent(e);
18625 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18626 * that it has registered. This method has no default implementation and should be overridden to provide
18627 * node-specific processing if necessary.
18628 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18629 * {@link #getTargetFromEvent} for this node)
18630 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18631 * @param {Event} e The event
18632 * @param {Object} data An object containing arbitrary data supplied by the drag source
18634 onNodeEnter : function(n, dd, e, data){
18639 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18640 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18641 * overridden to provide the proper feedback.
18642 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18643 * {@link #getTargetFromEvent} for this node)
18644 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18645 * @param {Event} e The event
18646 * @param {Object} data An object containing arbitrary data supplied by the drag source
18647 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18648 * underlying {@link Roo.dd.StatusProxy} can be updated
18650 onNodeOver : function(n, dd, e, data){
18651 return this.dropAllowed;
18655 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18656 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18657 * node-specific processing if necessary.
18658 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18659 * {@link #getTargetFromEvent} for this node)
18660 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18661 * @param {Event} e The event
18662 * @param {Object} data An object containing arbitrary data supplied by the drag source
18664 onNodeOut : function(n, dd, e, data){
18669 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18670 * the drop node. The default implementation returns false, so it should be overridden to provide the
18671 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18672 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18673 * {@link #getTargetFromEvent} for this node)
18674 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18675 * @param {Event} e The event
18676 * @param {Object} data An object containing arbitrary data supplied by the drag source
18677 * @return {Boolean} True if the drop was valid, else false
18679 onNodeDrop : function(n, dd, e, data){
18684 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18685 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18686 * it should be overridden to provide the proper feedback if necessary.
18687 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18688 * @param {Event} e The event
18689 * @param {Object} data An object containing arbitrary data supplied by the drag source
18690 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18691 * underlying {@link Roo.dd.StatusProxy} can be updated
18693 onContainerOver : function(dd, e, data){
18694 return this.dropNotAllowed;
18698 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18699 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18700 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18701 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18702 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18703 * @param {Event} e The event
18704 * @param {Object} data An object containing arbitrary data supplied by the drag source
18705 * @return {Boolean} True if the drop was valid, else false
18707 onContainerDrop : function(dd, e, data){
18712 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18713 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18714 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18715 * you should override this method and provide a custom implementation.
18716 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18717 * @param {Event} e The event
18718 * @param {Object} data An object containing arbitrary data supplied by the drag source
18719 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18720 * underlying {@link Roo.dd.StatusProxy} can be updated
18722 notifyEnter : function(dd, e, data){
18723 return this.dropNotAllowed;
18727 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18728 * This method will be called on every mouse movement while the drag source is over the drop zone.
18729 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18730 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18731 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18732 * registered node, it will call {@link #onContainerOver}.
18733 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18734 * @param {Event} e The event
18735 * @param {Object} data An object containing arbitrary data supplied by the drag source
18736 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18737 * underlying {@link Roo.dd.StatusProxy} can be updated
18739 notifyOver : function(dd, e, data){
18740 var n = this.getTargetFromEvent(e);
18741 if(!n){ // not over valid drop target
18742 if(this.lastOverNode){
18743 this.onNodeOut(this.lastOverNode, dd, e, data);
18744 this.lastOverNode = null;
18746 return this.onContainerOver(dd, e, data);
18748 if(this.lastOverNode != n){
18749 if(this.lastOverNode){
18750 this.onNodeOut(this.lastOverNode, dd, e, data);
18752 this.onNodeEnter(n, dd, e, data);
18753 this.lastOverNode = n;
18755 return this.onNodeOver(n, dd, e, data);
18759 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18760 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18761 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18762 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18763 * @param {Event} e The event
18764 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18766 notifyOut : function(dd, e, data){
18767 if(this.lastOverNode){
18768 this.onNodeOut(this.lastOverNode, dd, e, data);
18769 this.lastOverNode = null;
18774 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18775 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18776 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18777 * otherwise it will call {@link #onContainerDrop}.
18778 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18779 * @param {Event} e The event
18780 * @param {Object} data An object containing arbitrary data supplied by the drag source
18781 * @return {Boolean} True if the drop was valid, else false
18783 notifyDrop : function(dd, e, data){
18784 if(this.lastOverNode){
18785 this.onNodeOut(this.lastOverNode, dd, e, data);
18786 this.lastOverNode = null;
18788 var n = this.getTargetFromEvent(e);
18790 this.onNodeDrop(n, dd, e, data) :
18791 this.onContainerDrop(dd, e, data);
18795 triggerCacheRefresh : function(){
18796 Roo.dd.DDM.refreshCache(this.groups);
18800 * Ext JS Library 1.1.1
18801 * Copyright(c) 2006-2007, Ext JS, LLC.
18803 * Originally Released Under LGPL - original licence link has changed is not relivant.
18806 * <script type="text/javascript">
18811 * @class Roo.data.SortTypes
18813 * Defines the default sorting (casting?) comparison functions used when sorting data.
18815 Roo.data.SortTypes = {
18817 * Default sort that does nothing
18818 * @param {Mixed} s The value being converted
18819 * @return {Mixed} The comparison value
18821 none : function(s){
18826 * The regular expression used to strip tags
18830 stripTagsRE : /<\/?[^>]+>/gi,
18833 * Strips all HTML tags to sort on text only
18834 * @param {Mixed} s The value being converted
18835 * @return {String} The comparison value
18837 asText : function(s){
18838 return String(s).replace(this.stripTagsRE, "");
18842 * Strips all HTML tags to sort on text only - Case insensitive
18843 * @param {Mixed} s The value being converted
18844 * @return {String} The comparison value
18846 asUCText : function(s){
18847 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18851 * Case insensitive string
18852 * @param {Mixed} s The value being converted
18853 * @return {String} The comparison value
18855 asUCString : function(s) {
18856 return String(s).toUpperCase();
18861 * @param {Mixed} s The value being converted
18862 * @return {Number} The comparison value
18864 asDate : function(s) {
18868 if(s instanceof Date){
18869 return s.getTime();
18871 return Date.parse(String(s));
18876 * @param {Mixed} s The value being converted
18877 * @return {Float} The comparison value
18879 asFloat : function(s) {
18880 var val = parseFloat(String(s).replace(/,/g, ""));
18881 if(isNaN(val)) val = 0;
18887 * @param {Mixed} s The value being converted
18888 * @return {Number} The comparison value
18890 asInt : function(s) {
18891 var val = parseInt(String(s).replace(/,/g, ""));
18892 if(isNaN(val)) val = 0;
18897 * Ext JS Library 1.1.1
18898 * Copyright(c) 2006-2007, Ext JS, LLC.
18900 * Originally Released Under LGPL - original licence link has changed is not relivant.
18903 * <script type="text/javascript">
18907 * @class Roo.data.Record
18908 * Instances of this class encapsulate both record <em>definition</em> information, and record
18909 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18910 * to access Records cached in an {@link Roo.data.Store} object.<br>
18912 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18913 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18916 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18918 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18919 * {@link #create}. The parameters are the same.
18920 * @param {Array} data An associative Array of data values keyed by the field name.
18921 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18922 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18923 * not specified an integer id is generated.
18925 Roo.data.Record = function(data, id){
18926 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18931 * Generate a constructor for a specific record layout.
18932 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18933 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18934 * Each field definition object may contain the following properties: <ul>
18935 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
18936 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18937 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18938 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18939 * is being used, then this is a string containing the javascript expression to reference the data relative to
18940 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18941 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18942 * this may be omitted.</p></li>
18943 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18944 * <ul><li>auto (Default, implies no conversion)</li>
18949 * <li>date</li></ul></p></li>
18950 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18951 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18952 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18953 * by the Reader into an object that will be stored in the Record. It is passed the
18954 * following parameters:<ul>
18955 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18957 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18959 * <br>usage:<br><pre><code>
18960 var TopicRecord = Roo.data.Record.create(
18961 {name: 'title', mapping: 'topic_title'},
18962 {name: 'author', mapping: 'username'},
18963 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18964 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18965 {name: 'lastPoster', mapping: 'user2'},
18966 {name: 'excerpt', mapping: 'post_text'}
18969 var myNewRecord = new TopicRecord({
18970 title: 'Do my job please',
18973 lastPost: new Date(),
18974 lastPoster: 'Animal',
18975 excerpt: 'No way dude!'
18977 myStore.add(myNewRecord);
18982 Roo.data.Record.create = function(o){
18983 var f = function(){
18984 f.superclass.constructor.apply(this, arguments);
18986 Roo.extend(f, Roo.data.Record);
18987 var p = f.prototype;
18988 p.fields = new Roo.util.MixedCollection(false, function(field){
18991 for(var i = 0, len = o.length; i < len; i++){
18992 p.fields.add(new Roo.data.Field(o[i]));
18994 f.getField = function(name){
18995 return p.fields.get(name);
19000 Roo.data.Record.AUTO_ID = 1000;
19001 Roo.data.Record.EDIT = 'edit';
19002 Roo.data.Record.REJECT = 'reject';
19003 Roo.data.Record.COMMIT = 'commit';
19005 Roo.data.Record.prototype = {
19007 * Readonly flag - true if this record has been modified.
19016 join : function(store){
19017 this.store = store;
19021 * Set the named field to the specified value.
19022 * @param {String} name The name of the field to set.
19023 * @param {Object} value The value to set the field to.
19025 set : function(name, value){
19026 if(this.data[name] == value){
19030 if(!this.modified){
19031 this.modified = {};
19033 if(typeof this.modified[name] == 'undefined'){
19034 this.modified[name] = this.data[name];
19036 this.data[name] = value;
19038 this.store.afterEdit(this);
19043 * Get the value of the named field.
19044 * @param {String} name The name of the field to get the value of.
19045 * @return {Object} The value of the field.
19047 get : function(name){
19048 return this.data[name];
19052 beginEdit : function(){
19053 this.editing = true;
19054 this.modified = {};
19058 cancelEdit : function(){
19059 this.editing = false;
19060 delete this.modified;
19064 endEdit : function(){
19065 this.editing = false;
19066 if(this.dirty && this.store){
19067 this.store.afterEdit(this);
19072 * Usually called by the {@link Roo.data.Store} which owns the Record.
19073 * Rejects all changes made to the Record since either creation, or the last commit operation.
19074 * Modified fields are reverted to their original values.
19076 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19077 * of reject operations.
19079 reject : function(){
19080 var m = this.modified;
19082 if(typeof m[n] != "function"){
19083 this.data[n] = m[n];
19086 this.dirty = false;
19087 delete this.modified;
19088 this.editing = false;
19090 this.store.afterReject(this);
19095 * Usually called by the {@link Roo.data.Store} which owns the Record.
19096 * Commits all changes made to the Record since either creation, or the last commit operation.
19098 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19099 * of commit operations.
19101 commit : function(){
19102 this.dirty = false;
19103 delete this.modified;
19104 this.editing = false;
19106 this.store.afterCommit(this);
19111 hasError : function(){
19112 return this.error != null;
19116 clearError : function(){
19121 * Creates a copy of this record.
19122 * @param {String} id (optional) A new record id if you don't want to use this record's id
19125 copy : function(newId) {
19126 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19130 * Ext JS Library 1.1.1
19131 * Copyright(c) 2006-2007, Ext JS, LLC.
19133 * Originally Released Under LGPL - original licence link has changed is not relivant.
19136 * <script type="text/javascript">
19142 * @class Roo.data.Store
19143 * @extends Roo.util.Observable
19144 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19145 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19147 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
19148 * has no knowledge of the format of the data returned by the Proxy.<br>
19150 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19151 * instances from the data object. These records are cached and made available through accessor functions.
19153 * Creates a new Store.
19154 * @param {Object} config A config object containing the objects needed for the Store to access data,
19155 * and read the data into Records.
19157 Roo.data.Store = function(config){
19158 this.data = new Roo.util.MixedCollection(false);
19159 this.data.getKey = function(o){
19162 this.baseParams = {};
19164 this.paramNames = {
19169 "multisort" : "_multisort"
19172 if(config && config.data){
19173 this.inlineData = config.data;
19174 delete config.data;
19177 Roo.apply(this, config);
19179 if(this.reader){ // reader passed
19180 this.reader = Roo.factory(this.reader, Roo.data);
19181 this.reader.xmodule = this.xmodule || false;
19182 if(!this.recordType){
19183 this.recordType = this.reader.recordType;
19185 if(this.reader.onMetaChange){
19186 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19190 if(this.recordType){
19191 this.fields = this.recordType.prototype.fields;
19193 this.modified = [];
19197 * @event datachanged
19198 * Fires when the data cache has changed, and a widget which is using this Store
19199 * as a Record cache should refresh its view.
19200 * @param {Store} this
19202 datachanged : true,
19204 * @event metachange
19205 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19206 * @param {Store} this
19207 * @param {Object} meta The JSON metadata
19212 * Fires when Records have been added to the Store
19213 * @param {Store} this
19214 * @param {Roo.data.Record[]} records The array of Records added
19215 * @param {Number} index The index at which the record(s) were added
19220 * Fires when a Record has been removed from the Store
19221 * @param {Store} this
19222 * @param {Roo.data.Record} record The Record that was removed
19223 * @param {Number} index The index at which the record was removed
19228 * Fires when a Record has been updated
19229 * @param {Store} this
19230 * @param {Roo.data.Record} record The Record that was updated
19231 * @param {String} operation The update operation being performed. Value may be one of:
19233 Roo.data.Record.EDIT
19234 Roo.data.Record.REJECT
19235 Roo.data.Record.COMMIT
19241 * Fires when the data cache has been cleared.
19242 * @param {Store} this
19246 * @event beforeload
19247 * Fires before a request is made for a new data object. If the beforeload handler returns false
19248 * the load action will be canceled.
19249 * @param {Store} this
19250 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19255 * Fires after a new set of Records has been loaded.
19256 * @param {Store} this
19257 * @param {Roo.data.Record[]} records The Records that were loaded
19258 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19262 * @event loadexception
19263 * Fires if an exception occurs in the Proxy during loading.
19264 * Called with the signature of the Proxy's "loadexception" event.
19265 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19268 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19269 * @param {Object} load options
19270 * @param {Object} jsonData from your request (normally this contains the Exception)
19272 loadexception : true
19276 this.proxy = Roo.factory(this.proxy, Roo.data);
19277 this.proxy.xmodule = this.xmodule || false;
19278 this.relayEvents(this.proxy, ["loadexception"]);
19280 this.sortToggle = {};
19281 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19283 Roo.data.Store.superclass.constructor.call(this);
19285 if(this.inlineData){
19286 this.loadData(this.inlineData);
19287 delete this.inlineData;
19290 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19292 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19293 * without a remote query - used by combo/forms at present.
19297 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19300 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19303 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19304 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19307 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19308 * on any HTTP request
19311 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19314 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19318 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19319 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19321 remoteSort : false,
19324 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19325 * loaded or when a record is removed. (defaults to false).
19327 pruneModifiedRecords : false,
19330 lastOptions : null,
19333 * Add Records to the Store and fires the add event.
19334 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19336 add : function(records){
19337 records = [].concat(records);
19338 for(var i = 0, len = records.length; i < len; i++){
19339 records[i].join(this);
19341 var index = this.data.length;
19342 this.data.addAll(records);
19343 this.fireEvent("add", this, records, index);
19347 * Remove a Record from the Store and fires the remove event.
19348 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19350 remove : function(record){
19351 var index = this.data.indexOf(record);
19352 this.data.removeAt(index);
19353 if(this.pruneModifiedRecords){
19354 this.modified.remove(record);
19356 this.fireEvent("remove", this, record, index);
19360 * Remove all Records from the Store and fires the clear event.
19362 removeAll : function(){
19364 if(this.pruneModifiedRecords){
19365 this.modified = [];
19367 this.fireEvent("clear", this);
19371 * Inserts Records to the Store at the given index and fires the add event.
19372 * @param {Number} index The start index at which to insert the passed Records.
19373 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19375 insert : function(index, records){
19376 records = [].concat(records);
19377 for(var i = 0, len = records.length; i < len; i++){
19378 this.data.insert(index, records[i]);
19379 records[i].join(this);
19381 this.fireEvent("add", this, records, index);
19385 * Get the index within the cache of the passed Record.
19386 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19387 * @return {Number} The index of the passed Record. Returns -1 if not found.
19389 indexOf : function(record){
19390 return this.data.indexOf(record);
19394 * Get the index within the cache of the Record with the passed id.
19395 * @param {String} id The id of the Record to find.
19396 * @return {Number} The index of the Record. Returns -1 if not found.
19398 indexOfId : function(id){
19399 return this.data.indexOfKey(id);
19403 * Get the Record with the specified id.
19404 * @param {String} id The id of the Record to find.
19405 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19407 getById : function(id){
19408 return this.data.key(id);
19412 * Get the Record at the specified index.
19413 * @param {Number} index The index of the Record to find.
19414 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19416 getAt : function(index){
19417 return this.data.itemAt(index);
19421 * Returns a range of Records between specified indices.
19422 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19423 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19424 * @return {Roo.data.Record[]} An array of Records
19426 getRange : function(start, end){
19427 return this.data.getRange(start, end);
19431 storeOptions : function(o){
19432 o = Roo.apply({}, o);
19435 this.lastOptions = o;
19439 * Loads the Record cache from the configured Proxy using the configured Reader.
19441 * If using remote paging, then the first load call must specify the <em>start</em>
19442 * and <em>limit</em> properties in the options.params property to establish the initial
19443 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19445 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19446 * and this call will return before the new data has been loaded. Perform any post-processing
19447 * in a callback function, or in a "load" event handler.</strong>
19449 * @param {Object} options An object containing properties which control loading options:<ul>
19450 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19451 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19452 * passed the following arguments:<ul>
19453 * <li>r : Roo.data.Record[]</li>
19454 * <li>options: Options object from the load call</li>
19455 * <li>success: Boolean success indicator</li></ul></li>
19456 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19457 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19460 load : function(options){
19461 options = options || {};
19462 if(this.fireEvent("beforeload", this, options) !== false){
19463 this.storeOptions(options);
19464 var p = Roo.apply(options.params || {}, this.baseParams);
19465 // if meta was not loaded from remote source.. try requesting it.
19466 if (!this.reader.metaFromRemote) {
19467 p._requestMeta = 1;
19469 if(this.sortInfo && this.remoteSort){
19470 var pn = this.paramNames;
19471 p[pn["sort"]] = this.sortInfo.field;
19472 p[pn["dir"]] = this.sortInfo.direction;
19474 if (this.multiSort) {
19475 var pn = this.paramNames;
19476 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19479 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19484 * Reloads the Record cache from the configured Proxy using the configured Reader and
19485 * the options from the last load operation performed.
19486 * @param {Object} options (optional) An object containing properties which may override the options
19487 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19488 * the most recently used options are reused).
19490 reload : function(options){
19491 this.load(Roo.applyIf(options||{}, this.lastOptions));
19495 // Called as a callback by the Reader during a load operation.
19496 loadRecords : function(o, options, success){
19497 if(!o || success === false){
19498 if(success !== false){
19499 this.fireEvent("load", this, [], options);
19501 if(options.callback){
19502 options.callback.call(options.scope || this, [], options, false);
19506 // if data returned failure - throw an exception.
19507 if (o.success === false) {
19508 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19511 var r = o.records, t = o.totalRecords || r.length;
19512 if(!options || options.add !== true){
19513 if(this.pruneModifiedRecords){
19514 this.modified = [];
19516 for(var i = 0, len = r.length; i < len; i++){
19520 this.data = this.snapshot;
19521 delete this.snapshot;
19524 this.data.addAll(r);
19525 this.totalLength = t;
19527 this.fireEvent("datachanged", this);
19529 this.totalLength = Math.max(t, this.data.length+r.length);
19532 this.fireEvent("load", this, r, options);
19533 if(options.callback){
19534 options.callback.call(options.scope || this, r, options, true);
19539 * Loads data from a passed data block. A Reader which understands the format of the data
19540 * must have been configured in the constructor.
19541 * @param {Object} data The data block from which to read the Records. The format of the data expected
19542 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19543 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19545 loadData : function(o, append){
19546 var r = this.reader.readRecords(o);
19547 this.loadRecords(r, {add: append}, true);
19551 * Gets the number of cached records.
19553 * <em>If using paging, this may not be the total size of the dataset. If the data object
19554 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19555 * the data set size</em>
19557 getCount : function(){
19558 return this.data.length || 0;
19562 * Gets the total number of records in the dataset as returned by the server.
19564 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19565 * the dataset size</em>
19567 getTotalCount : function(){
19568 return this.totalLength || 0;
19572 * Returns the sort state of the Store as an object with two properties:
19574 field {String} The name of the field by which the Records are sorted
19575 direction {String} The sort order, "ASC" or "DESC"
19578 getSortState : function(){
19579 return this.sortInfo;
19583 applySort : function(){
19584 if(this.sortInfo && !this.remoteSort){
19585 var s = this.sortInfo, f = s.field;
19586 var st = this.fields.get(f).sortType;
19587 var fn = function(r1, r2){
19588 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19589 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19591 this.data.sort(s.direction, fn);
19592 if(this.snapshot && this.snapshot != this.data){
19593 this.snapshot.sort(s.direction, fn);
19599 * Sets the default sort column and order to be used by the next load operation.
19600 * @param {String} fieldName The name of the field to sort by.
19601 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19603 setDefaultSort : function(field, dir){
19604 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19608 * Sort the Records.
19609 * If remote sorting is used, the sort is performed on the server, and the cache is
19610 * reloaded. If local sorting is used, the cache is sorted internally.
19611 * @param {String} fieldName The name of the field to sort by.
19612 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19614 sort : function(fieldName, dir){
19615 var f = this.fields.get(fieldName);
19617 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19619 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19620 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19625 this.sortToggle[f.name] = dir;
19626 this.sortInfo = {field: f.name, direction: dir};
19627 if(!this.remoteSort){
19629 this.fireEvent("datachanged", this);
19631 this.load(this.lastOptions);
19636 * Calls the specified function for each of the Records in the cache.
19637 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19638 * Returning <em>false</em> aborts and exits the iteration.
19639 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19641 each : function(fn, scope){
19642 this.data.each(fn, scope);
19646 * Gets all records modified since the last commit. Modified records are persisted across load operations
19647 * (e.g., during paging).
19648 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19650 getModifiedRecords : function(){
19651 return this.modified;
19655 createFilterFn : function(property, value, anyMatch){
19656 if(!value.exec){ // not a regex
19657 value = String(value);
19658 if(value.length == 0){
19661 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19663 return function(r){
19664 return value.test(r.data[property]);
19669 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19670 * @param {String} property A field on your records
19671 * @param {Number} start The record index to start at (defaults to 0)
19672 * @param {Number} end The last record index to include (defaults to length - 1)
19673 * @return {Number} The sum
19675 sum : function(property, start, end){
19676 var rs = this.data.items, v = 0;
19677 start = start || 0;
19678 end = (end || end === 0) ? end : rs.length-1;
19680 for(var i = start; i <= end; i++){
19681 v += (rs[i].data[property] || 0);
19687 * Filter the records by a specified property.
19688 * @param {String} field A field on your records
19689 * @param {String/RegExp} value Either a string that the field
19690 * should start with or a RegExp to test against the field
19691 * @param {Boolean} anyMatch True to match any part not just the beginning
19693 filter : function(property, value, anyMatch){
19694 var fn = this.createFilterFn(property, value, anyMatch);
19695 return fn ? this.filterBy(fn) : this.clearFilter();
19699 * Filter by a function. The specified function will be called with each
19700 * record in this data source. If the function returns true the record is included,
19701 * otherwise it is filtered.
19702 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19703 * @param {Object} scope (optional) The scope of the function (defaults to this)
19705 filterBy : function(fn, scope){
19706 this.snapshot = this.snapshot || this.data;
19707 this.data = this.queryBy(fn, scope||this);
19708 this.fireEvent("datachanged", this);
19712 * Query the records by a specified property.
19713 * @param {String} field A field on your records
19714 * @param {String/RegExp} value Either a string that the field
19715 * should start with or a RegExp to test against the field
19716 * @param {Boolean} anyMatch True to match any part not just the beginning
19717 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19719 query : function(property, value, anyMatch){
19720 var fn = this.createFilterFn(property, value, anyMatch);
19721 return fn ? this.queryBy(fn) : this.data.clone();
19725 * Query by a function. The specified function will be called with each
19726 * record in this data source. If the function returns true the record is included
19728 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19729 * @param {Object} scope (optional) The scope of the function (defaults to this)
19730 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19732 queryBy : function(fn, scope){
19733 var data = this.snapshot || this.data;
19734 return data.filterBy(fn, scope||this);
19738 * Collects unique values for a particular dataIndex from this store.
19739 * @param {String} dataIndex The property to collect
19740 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19741 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19742 * @return {Array} An array of the unique values
19744 collect : function(dataIndex, allowNull, bypassFilter){
19745 var d = (bypassFilter === true && this.snapshot) ?
19746 this.snapshot.items : this.data.items;
19747 var v, sv, r = [], l = {};
19748 for(var i = 0, len = d.length; i < len; i++){
19749 v = d[i].data[dataIndex];
19751 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19760 * Revert to a view of the Record cache with no filtering applied.
19761 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19763 clearFilter : function(suppressEvent){
19764 if(this.snapshot && this.snapshot != this.data){
19765 this.data = this.snapshot;
19766 delete this.snapshot;
19767 if(suppressEvent !== true){
19768 this.fireEvent("datachanged", this);
19774 afterEdit : function(record){
19775 if(this.modified.indexOf(record) == -1){
19776 this.modified.push(record);
19778 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19782 afterReject : function(record){
19783 this.modified.remove(record);
19784 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19788 afterCommit : function(record){
19789 this.modified.remove(record);
19790 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19794 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19795 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19797 commitChanges : function(){
19798 var m = this.modified.slice(0);
19799 this.modified = [];
19800 for(var i = 0, len = m.length; i < len; i++){
19806 * Cancel outstanding changes on all changed records.
19808 rejectChanges : function(){
19809 var m = this.modified.slice(0);
19810 this.modified = [];
19811 for(var i = 0, len = m.length; i < len; i++){
19816 onMetaChange : function(meta, rtype, o){
19817 this.recordType = rtype;
19818 this.fields = rtype.prototype.fields;
19819 delete this.snapshot;
19820 this.sortInfo = meta.sortInfo || this.sortInfo;
19821 this.modified = [];
19822 this.fireEvent('metachange', this, this.reader.meta);
19826 * Ext JS Library 1.1.1
19827 * Copyright(c) 2006-2007, Ext JS, LLC.
19829 * Originally Released Under LGPL - original licence link has changed is not relivant.
19832 * <script type="text/javascript">
19836 * @class Roo.data.SimpleStore
19837 * @extends Roo.data.Store
19838 * Small helper class to make creating Stores from Array data easier.
19839 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19840 * @cfg {Array} fields An array of field definition objects, or field name strings.
19841 * @cfg {Array} data The multi-dimensional array of data
19843 * @param {Object} config
19845 Roo.data.SimpleStore = function(config){
19846 Roo.data.SimpleStore.superclass.constructor.call(this, {
19848 reader: new Roo.data.ArrayReader({
19851 Roo.data.Record.create(config.fields)
19853 proxy : new Roo.data.MemoryProxy(config.data)
19857 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19859 * Ext JS Library 1.1.1
19860 * Copyright(c) 2006-2007, Ext JS, LLC.
19862 * Originally Released Under LGPL - original licence link has changed is not relivant.
19865 * <script type="text/javascript">
19870 * @extends Roo.data.Store
19871 * @class Roo.data.JsonStore
19872 * Small helper class to make creating Stores for JSON data easier. <br/>
19874 var store = new Roo.data.JsonStore({
19875 url: 'get-images.php',
19877 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19880 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19881 * JsonReader and HttpProxy (unless inline data is provided).</b>
19882 * @cfg {Array} fields An array of field definition objects, or field name strings.
19884 * @param {Object} config
19886 Roo.data.JsonStore = function(c){
19887 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19888 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19889 reader: new Roo.data.JsonReader(c, c.fields)
19892 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19894 * Ext JS Library 1.1.1
19895 * Copyright(c) 2006-2007, Ext JS, LLC.
19897 * Originally Released Under LGPL - original licence link has changed is not relivant.
19900 * <script type="text/javascript">
19904 Roo.data.Field = function(config){
19905 if(typeof config == "string"){
19906 config = {name: config};
19908 Roo.apply(this, config);
19911 this.type = "auto";
19914 var st = Roo.data.SortTypes;
19915 // named sortTypes are supported, here we look them up
19916 if(typeof this.sortType == "string"){
19917 this.sortType = st[this.sortType];
19920 // set default sortType for strings and dates
19921 if(!this.sortType){
19924 this.sortType = st.asUCString;
19927 this.sortType = st.asDate;
19930 this.sortType = st.none;
19935 var stripRe = /[\$,%]/g;
19937 // prebuilt conversion function for this field, instead of
19938 // switching every time we're reading a value
19940 var cv, dateFormat = this.dateFormat;
19945 cv = function(v){ return v; };
19948 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19952 return v !== undefined && v !== null && v !== '' ?
19953 parseInt(String(v).replace(stripRe, ""), 10) : '';
19958 return v !== undefined && v !== null && v !== '' ?
19959 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19964 cv = function(v){ return v === true || v === "true" || v == 1; };
19971 if(v instanceof Date){
19975 if(dateFormat == "timestamp"){
19976 return new Date(v*1000);
19978 return Date.parseDate(v, dateFormat);
19980 var parsed = Date.parse(v);
19981 return parsed ? new Date(parsed) : null;
19990 Roo.data.Field.prototype = {
19998 * Ext JS Library 1.1.1
19999 * Copyright(c) 2006-2007, Ext JS, LLC.
20001 * Originally Released Under LGPL - original licence link has changed is not relivant.
20004 * <script type="text/javascript">
20007 // Base class for reading structured data from a data source. This class is intended to be
20008 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20011 * @class Roo.data.DataReader
20012 * Base class for reading structured data from a data source. This class is intended to be
20013 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20016 Roo.data.DataReader = function(meta, recordType){
20020 this.recordType = recordType instanceof Array ?
20021 Roo.data.Record.create(recordType) : recordType;
20024 Roo.data.DataReader.prototype = {
20026 * Create an empty record
20027 * @param {Object} data (optional) - overlay some values
20028 * @return {Roo.data.Record} record created.
20030 newRow : function(d) {
20032 this.recordType.prototype.fields.each(function(c) {
20034 case 'int' : da[c.name] = 0; break;
20035 case 'date' : da[c.name] = new Date(); break;
20036 case 'float' : da[c.name] = 0.0; break;
20037 case 'boolean' : da[c.name] = false; break;
20038 default : da[c.name] = ""; break;
20042 return new this.recordType(Roo.apply(da, d));
20047 * Ext JS Library 1.1.1
20048 * Copyright(c) 2006-2007, Ext JS, LLC.
20050 * Originally Released Under LGPL - original licence link has changed is not relivant.
20053 * <script type="text/javascript">
20057 * @class Roo.data.DataProxy
20058 * @extends Roo.data.Observable
20059 * This class is an abstract base class for implementations which provide retrieval of
20060 * unformatted data objects.<br>
20062 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20063 * (of the appropriate type which knows how to parse the data object) to provide a block of
20064 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20066 * Custom implementations must implement the load method as described in
20067 * {@link Roo.data.HttpProxy#load}.
20069 Roo.data.DataProxy = function(){
20072 * @event beforeload
20073 * Fires before a network request is made to retrieve a data object.
20074 * @param {Object} This DataProxy object.
20075 * @param {Object} params The params parameter to the load function.
20080 * Fires before the load method's callback is called.
20081 * @param {Object} This DataProxy object.
20082 * @param {Object} o The data object.
20083 * @param {Object} arg The callback argument object passed to the load function.
20087 * @event loadexception
20088 * Fires if an Exception occurs during data retrieval.
20089 * @param {Object} This DataProxy object.
20090 * @param {Object} o The data object.
20091 * @param {Object} arg The callback argument object passed to the load function.
20092 * @param {Object} e The Exception.
20094 loadexception : true
20096 Roo.data.DataProxy.superclass.constructor.call(this);
20099 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20102 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20106 * Ext JS Library 1.1.1
20107 * Copyright(c) 2006-2007, Ext JS, LLC.
20109 * Originally Released Under LGPL - original licence link has changed is not relivant.
20112 * <script type="text/javascript">
20115 * @class Roo.data.MemoryProxy
20116 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20117 * to the Reader when its load method is called.
20119 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20121 Roo.data.MemoryProxy = function(data){
20125 Roo.data.MemoryProxy.superclass.constructor.call(this);
20129 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20131 * Load data from the requested source (in this case an in-memory
20132 * data object passed to the constructor), read the data object into
20133 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20134 * process that block using the passed callback.
20135 * @param {Object} params This parameter is not used by the MemoryProxy class.
20136 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20137 * object into a block of Roo.data.Records.
20138 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20139 * The function must be passed <ul>
20140 * <li>The Record block object</li>
20141 * <li>The "arg" argument from the load function</li>
20142 * <li>A boolean success indicator</li>
20144 * @param {Object} scope The scope in which to call the callback
20145 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20147 load : function(params, reader, callback, scope, arg){
20148 params = params || {};
20151 result = reader.readRecords(this.data);
20153 this.fireEvent("loadexception", this, arg, null, e);
20154 callback.call(scope, null, arg, false);
20157 callback.call(scope, result, arg, true);
20161 update : function(params, records){
20166 * Ext JS Library 1.1.1
20167 * Copyright(c) 2006-2007, Ext JS, LLC.
20169 * Originally Released Under LGPL - original licence link has changed is not relivant.
20172 * <script type="text/javascript">
20175 * @class Roo.data.HttpProxy
20176 * @extends Roo.data.DataProxy
20177 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20178 * configured to reference a certain URL.<br><br>
20180 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20181 * from which the running page was served.<br><br>
20183 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20185 * Be aware that to enable the browser to parse an XML document, the server must set
20186 * the Content-Type header in the HTTP response to "text/xml".
20188 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20189 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20190 * will be used to make the request.
20192 Roo.data.HttpProxy = function(conn){
20193 Roo.data.HttpProxy.superclass.constructor.call(this);
20194 // is conn a conn config or a real conn?
20196 this.useAjax = !conn || !conn.events;
20200 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20201 // thse are take from connection...
20204 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20207 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20208 * extra parameters to each request made by this object. (defaults to undefined)
20211 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20212 * to each request made by this object. (defaults to undefined)
20215 * @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)
20218 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20221 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20227 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20231 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20232 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20233 * a finer-grained basis than the DataProxy events.
20235 getConnection : function(){
20236 return this.useAjax ? Roo.Ajax : this.conn;
20240 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20241 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20242 * process that block using the passed callback.
20243 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20244 * for the request to the remote server.
20245 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20246 * object into a block of Roo.data.Records.
20247 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20248 * The function must be passed <ul>
20249 * <li>The Record block object</li>
20250 * <li>The "arg" argument from the load function</li>
20251 * <li>A boolean success indicator</li>
20253 * @param {Object} scope The scope in which to call the callback
20254 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20256 load : function(params, reader, callback, scope, arg){
20257 if(this.fireEvent("beforeload", this, params) !== false){
20259 params : params || {},
20261 callback : callback,
20266 callback : this.loadResponse,
20270 Roo.applyIf(o, this.conn);
20271 if(this.activeRequest){
20272 Roo.Ajax.abort(this.activeRequest);
20274 this.activeRequest = Roo.Ajax.request(o);
20276 this.conn.request(o);
20279 callback.call(scope||this, null, arg, false);
20284 loadResponse : function(o, success, response){
20285 delete this.activeRequest;
20287 this.fireEvent("loadexception", this, o, response);
20288 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20293 result = o.reader.read(response);
20295 this.fireEvent("loadexception", this, o, response, e);
20296 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20300 this.fireEvent("load", this, o, o.request.arg);
20301 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20305 update : function(dataSet){
20310 updateResponse : function(dataSet){
20315 * Ext JS Library 1.1.1
20316 * Copyright(c) 2006-2007, Ext JS, LLC.
20318 * Originally Released Under LGPL - original licence link has changed is not relivant.
20321 * <script type="text/javascript">
20325 * @class Roo.data.ScriptTagProxy
20326 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20327 * other than the originating domain of the running page.<br><br>
20329 * <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
20330 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20332 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20333 * source code that is used as the source inside a <script> tag.<br><br>
20335 * In order for the browser to process the returned data, the server must wrap the data object
20336 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20337 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20338 * depending on whether the callback name was passed:
20341 boolean scriptTag = false;
20342 String cb = request.getParameter("callback");
20345 response.setContentType("text/javascript");
20347 response.setContentType("application/x-json");
20349 Writer out = response.getWriter();
20351 out.write(cb + "(");
20353 out.print(dataBlock.toJsonString());
20360 * @param {Object} config A configuration object.
20362 Roo.data.ScriptTagProxy = function(config){
20363 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20364 Roo.apply(this, config);
20365 this.head = document.getElementsByTagName("head")[0];
20368 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20370 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20372 * @cfg {String} url The URL from which to request the data object.
20375 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20379 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20380 * the server the name of the callback function set up by the load call to process the returned data object.
20381 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20382 * javascript output which calls this named function passing the data object as its only parameter.
20384 callbackParam : "callback",
20386 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20387 * name to the request.
20392 * Load data from the configured URL, read the data object into
20393 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20394 * process that block using the passed callback.
20395 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20396 * for the request to the remote server.
20397 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20398 * object into a block of Roo.data.Records.
20399 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20400 * The function must be passed <ul>
20401 * <li>The Record block object</li>
20402 * <li>The "arg" argument from the load function</li>
20403 * <li>A boolean success indicator</li>
20405 * @param {Object} scope The scope in which to call the callback
20406 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20408 load : function(params, reader, callback, scope, arg){
20409 if(this.fireEvent("beforeload", this, params) !== false){
20411 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20413 var url = this.url;
20414 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20416 url += "&_dc=" + (new Date().getTime());
20418 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20421 cb : "stcCallback"+transId,
20422 scriptId : "stcScript"+transId,
20426 callback : callback,
20432 window[trans.cb] = function(o){
20433 conn.handleResponse(o, trans);
20436 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20438 if(this.autoAbort !== false){
20442 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20444 var script = document.createElement("script");
20445 script.setAttribute("src", url);
20446 script.setAttribute("type", "text/javascript");
20447 script.setAttribute("id", trans.scriptId);
20448 this.head.appendChild(script);
20450 this.trans = trans;
20452 callback.call(scope||this, null, arg, false);
20457 isLoading : function(){
20458 return this.trans ? true : false;
20462 * Abort the current server request.
20464 abort : function(){
20465 if(this.isLoading()){
20466 this.destroyTrans(this.trans);
20471 destroyTrans : function(trans, isLoaded){
20472 this.head.removeChild(document.getElementById(trans.scriptId));
20473 clearTimeout(trans.timeoutId);
20475 window[trans.cb] = undefined;
20477 delete window[trans.cb];
20480 // if hasn't been loaded, wait for load to remove it to prevent script error
20481 window[trans.cb] = function(){
20482 window[trans.cb] = undefined;
20484 delete window[trans.cb];
20491 handleResponse : function(o, trans){
20492 this.trans = false;
20493 this.destroyTrans(trans, true);
20496 result = trans.reader.readRecords(o);
20498 this.fireEvent("loadexception", this, o, trans.arg, e);
20499 trans.callback.call(trans.scope||window, null, trans.arg, false);
20502 this.fireEvent("load", this, o, trans.arg);
20503 trans.callback.call(trans.scope||window, result, trans.arg, true);
20507 handleFailure : function(trans){
20508 this.trans = false;
20509 this.destroyTrans(trans, false);
20510 this.fireEvent("loadexception", this, null, trans.arg);
20511 trans.callback.call(trans.scope||window, null, trans.arg, false);
20515 * Ext JS Library 1.1.1
20516 * Copyright(c) 2006-2007, Ext JS, LLC.
20518 * Originally Released Under LGPL - original licence link has changed is not relivant.
20521 * <script type="text/javascript">
20525 * @class Roo.data.JsonReader
20526 * @extends Roo.data.DataReader
20527 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20528 * based on mappings in a provided Roo.data.Record constructor.
20530 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20531 * in the reply previously.
20536 var RecordDef = Roo.data.Record.create([
20537 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20538 {name: 'occupation'} // This field will use "occupation" as the mapping.
20540 var myReader = new Roo.data.JsonReader({
20541 totalProperty: "results", // The property which contains the total dataset size (optional)
20542 root: "rows", // The property which contains an Array of row objects
20543 id: "id" // The property within each row object that provides an ID for the record (optional)
20547 * This would consume a JSON file like this:
20549 { 'results': 2, 'rows': [
20550 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20551 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20554 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20555 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20556 * paged from the remote server.
20557 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20558 * @cfg {String} root name of the property which contains the Array of row objects.
20559 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20561 * Create a new JsonReader
20562 * @param {Object} meta Metadata configuration options
20563 * @param {Object} recordType Either an Array of field definition objects,
20564 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20566 Roo.data.JsonReader = function(meta, recordType){
20569 // set some defaults:
20570 Roo.applyIf(meta, {
20571 totalProperty: 'total',
20572 successProperty : 'success',
20577 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20579 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20582 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20583 * Used by Store query builder to append _requestMeta to params.
20586 metaFromRemote : false,
20588 * This method is only used by a DataProxy which has retrieved data from a remote server.
20589 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20590 * @return {Object} data A data block which is used by an Roo.data.Store object as
20591 * a cache of Roo.data.Records.
20593 read : function(response){
20594 var json = response.responseText;
20596 var o = /* eval:var:o */ eval("("+json+")");
20598 throw {message: "JsonReader.read: Json object not found"};
20604 this.metaFromRemote = true;
20605 this.meta = o.metaData;
20606 this.recordType = Roo.data.Record.create(o.metaData.fields);
20607 this.onMetaChange(this.meta, this.recordType, o);
20609 return this.readRecords(o);
20612 // private function a store will implement
20613 onMetaChange : function(meta, recordType, o){
20620 simpleAccess: function(obj, subsc) {
20627 getJsonAccessor: function(){
20629 return function(expr) {
20631 return(re.test(expr))
20632 ? new Function("obj", "return obj." + expr)
20637 return Roo.emptyFn;
20642 * Create a data block containing Roo.data.Records from an XML document.
20643 * @param {Object} o An object which contains an Array of row objects in the property specified
20644 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20645 * which contains the total size of the dataset.
20646 * @return {Object} data A data block which is used by an Roo.data.Store object as
20647 * a cache of Roo.data.Records.
20649 readRecords : function(o){
20651 * After any data loads, the raw JSON data is available for further custom processing.
20655 var s = this.meta, Record = this.recordType,
20656 f = Record.prototype.fields, fi = f.items, fl = f.length;
20658 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20660 if(s.totalProperty) {
20661 this.getTotal = this.getJsonAccessor(s.totalProperty);
20663 if(s.successProperty) {
20664 this.getSuccess = this.getJsonAccessor(s.successProperty);
20666 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20668 var g = this.getJsonAccessor(s.id);
20669 this.getId = function(rec) {
20671 return (r === undefined || r === "") ? null : r;
20674 this.getId = function(){return null;};
20677 for(var jj = 0; jj < fl; jj++){
20679 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20680 this.ef[jj] = this.getJsonAccessor(map);
20684 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20685 if(s.totalProperty){
20686 var vt = parseInt(this.getTotal(o), 10);
20691 if(s.successProperty){
20692 var vs = this.getSuccess(o);
20693 if(vs === false || vs === 'false'){
20698 for(var i = 0; i < c; i++){
20701 var id = this.getId(n);
20702 for(var j = 0; j < fl; j++){
20704 var v = this.ef[j](n);
20706 Roo.log('missing convert for ' + f.name);
20710 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20712 var record = new Record(values, id);
20714 records[i] = record;
20719 totalRecords : totalRecords
20724 * Ext JS Library 1.1.1
20725 * Copyright(c) 2006-2007, Ext JS, LLC.
20727 * Originally Released Under LGPL - original licence link has changed is not relivant.
20730 * <script type="text/javascript">
20734 * @class Roo.data.XmlReader
20735 * @extends Roo.data.DataReader
20736 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20737 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20739 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20740 * header in the HTTP response must be set to "text/xml".</em>
20744 var RecordDef = Roo.data.Record.create([
20745 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20746 {name: 'occupation'} // This field will use "occupation" as the mapping.
20748 var myReader = new Roo.data.XmlReader({
20749 totalRecords: "results", // The element which contains the total dataset size (optional)
20750 record: "row", // The repeated element which contains row information
20751 id: "id" // The element within the row that provides an ID for the record (optional)
20755 * This would consume an XML file like this:
20759 <results>2</results>
20762 <name>Bill</name>
20763 <occupation>Gardener</occupation>
20767 <name>Ben</name>
20768 <occupation>Horticulturalist</occupation>
20772 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20773 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20774 * paged from the remote server.
20775 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20776 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20777 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20778 * a record identifier value.
20780 * Create a new XmlReader
20781 * @param {Object} meta Metadata configuration options
20782 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20783 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20784 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20786 Roo.data.XmlReader = function(meta, recordType){
20788 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20790 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20792 * This method is only used by a DataProxy which has retrieved data from a remote server.
20793 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20794 * to contain a method called 'responseXML' that returns an XML document object.
20795 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20796 * a cache of Roo.data.Records.
20798 read : function(response){
20799 var doc = response.responseXML;
20801 throw {message: "XmlReader.read: XML Document not available"};
20803 return this.readRecords(doc);
20807 * Create a data block containing Roo.data.Records from an XML document.
20808 * @param {Object} doc A parsed XML document.
20809 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20810 * a cache of Roo.data.Records.
20812 readRecords : function(doc){
20814 * After any data loads/reads, the raw XML Document is available for further custom processing.
20815 * @type XMLDocument
20817 this.xmlData = doc;
20818 var root = doc.documentElement || doc;
20819 var q = Roo.DomQuery;
20820 var recordType = this.recordType, fields = recordType.prototype.fields;
20821 var sid = this.meta.id;
20822 var totalRecords = 0, success = true;
20823 if(this.meta.totalRecords){
20824 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20827 if(this.meta.success){
20828 var sv = q.selectValue(this.meta.success, root, true);
20829 success = sv !== false && sv !== 'false';
20832 var ns = q.select(this.meta.record, root);
20833 for(var i = 0, len = ns.length; i < len; i++) {
20836 var id = sid ? q.selectValue(sid, n) : undefined;
20837 for(var j = 0, jlen = fields.length; j < jlen; j++){
20838 var f = fields.items[j];
20839 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20841 values[f.name] = v;
20843 var record = new recordType(values, id);
20845 records[records.length] = record;
20851 totalRecords : totalRecords || records.length
20856 * Ext JS Library 1.1.1
20857 * Copyright(c) 2006-2007, Ext JS, LLC.
20859 * Originally Released Under LGPL - original licence link has changed is not relivant.
20862 * <script type="text/javascript">
20866 * @class Roo.data.ArrayReader
20867 * @extends Roo.data.DataReader
20868 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20869 * Each element of that Array represents a row of data fields. The
20870 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20871 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20875 var RecordDef = Roo.data.Record.create([
20876 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20877 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20879 var myReader = new Roo.data.ArrayReader({
20880 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20884 * This would consume an Array like this:
20886 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20888 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20890 * Create a new JsonReader
20891 * @param {Object} meta Metadata configuration options.
20892 * @param {Object} recordType Either an Array of field definition objects
20893 * as specified to {@link Roo.data.Record#create},
20894 * or an {@link Roo.data.Record} object
20895 * created using {@link Roo.data.Record#create}.
20897 Roo.data.ArrayReader = function(meta, recordType){
20898 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20901 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20903 * Create a data block containing Roo.data.Records from an XML document.
20904 * @param {Object} o An Array of row objects which represents the dataset.
20905 * @return {Object} data A data block which is used by an Roo.data.Store object as
20906 * a cache of Roo.data.Records.
20908 readRecords : function(o){
20909 var sid = this.meta ? this.meta.id : null;
20910 var recordType = this.recordType, fields = recordType.prototype.fields;
20913 for(var i = 0; i < root.length; i++){
20916 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20917 for(var j = 0, jlen = fields.length; j < jlen; j++){
20918 var f = fields.items[j];
20919 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20920 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20922 values[f.name] = v;
20924 var record = new recordType(values, id);
20926 records[records.length] = record;
20930 totalRecords : records.length
20935 * Ext JS Library 1.1.1
20936 * Copyright(c) 2006-2007, Ext JS, LLC.
20938 * Originally Released Under LGPL - original licence link has changed is not relivant.
20941 * <script type="text/javascript">
20946 * @class Roo.data.Tree
20947 * @extends Roo.util.Observable
20948 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20949 * in the tree have most standard DOM functionality.
20951 * @param {Node} root (optional) The root node
20953 Roo.data.Tree = function(root){
20954 this.nodeHash = {};
20956 * The root node for this tree
20961 this.setRootNode(root);
20966 * Fires when a new child node is appended to a node in this tree.
20967 * @param {Tree} tree The owner tree
20968 * @param {Node} parent The parent node
20969 * @param {Node} node The newly appended node
20970 * @param {Number} index The index of the newly appended node
20975 * Fires when a child node is removed from a node in this tree.
20976 * @param {Tree} tree The owner tree
20977 * @param {Node} parent The parent node
20978 * @param {Node} node The child node removed
20983 * Fires when a node is moved to a new location in the tree
20984 * @param {Tree} tree The owner tree
20985 * @param {Node} node The node moved
20986 * @param {Node} oldParent The old parent of this node
20987 * @param {Node} newParent The new parent of this node
20988 * @param {Number} index The index it was moved to
20993 * Fires when a new child node is inserted in a node in this tree.
20994 * @param {Tree} tree The owner tree
20995 * @param {Node} parent The parent node
20996 * @param {Node} node The child node inserted
20997 * @param {Node} refNode The child node the node was inserted before
21001 * @event beforeappend
21002 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21003 * @param {Tree} tree The owner tree
21004 * @param {Node} parent The parent node
21005 * @param {Node} node The child node to be appended
21007 "beforeappend" : true,
21009 * @event beforeremove
21010 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21011 * @param {Tree} tree The owner tree
21012 * @param {Node} parent The parent node
21013 * @param {Node} node The child node to be removed
21015 "beforeremove" : true,
21017 * @event beforemove
21018 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21019 * @param {Tree} tree The owner tree
21020 * @param {Node} node The node being moved
21021 * @param {Node} oldParent The parent of the node
21022 * @param {Node} newParent The new parent the node is moving to
21023 * @param {Number} index The index it is being moved to
21025 "beforemove" : true,
21027 * @event beforeinsert
21028 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21029 * @param {Tree} tree The owner tree
21030 * @param {Node} parent The parent node
21031 * @param {Node} node The child node to be inserted
21032 * @param {Node} refNode The child node the node is being inserted before
21034 "beforeinsert" : true
21037 Roo.data.Tree.superclass.constructor.call(this);
21040 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21041 pathSeparator: "/",
21043 proxyNodeEvent : function(){
21044 return this.fireEvent.apply(this, arguments);
21048 * Returns the root node for this tree.
21051 getRootNode : function(){
21056 * Sets the root node for this tree.
21057 * @param {Node} node
21060 setRootNode : function(node){
21062 node.ownerTree = this;
21063 node.isRoot = true;
21064 this.registerNode(node);
21069 * Gets a node in this tree by its id.
21070 * @param {String} id
21073 getNodeById : function(id){
21074 return this.nodeHash[id];
21077 registerNode : function(node){
21078 this.nodeHash[node.id] = node;
21081 unregisterNode : function(node){
21082 delete this.nodeHash[node.id];
21085 toString : function(){
21086 return "[Tree"+(this.id?" "+this.id:"")+"]";
21091 * @class Roo.data.Node
21092 * @extends Roo.util.Observable
21093 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21094 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21096 * @param {Object} attributes The attributes/config for the node
21098 Roo.data.Node = function(attributes){
21100 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21103 this.attributes = attributes || {};
21104 this.leaf = this.attributes.leaf;
21106 * The node id. @type String
21108 this.id = this.attributes.id;
21110 this.id = Roo.id(null, "ynode-");
21111 this.attributes.id = this.id;
21114 * All child nodes of this node. @type Array
21116 this.childNodes = [];
21117 if(!this.childNodes.indexOf){ // indexOf is a must
21118 this.childNodes.indexOf = function(o){
21119 for(var i = 0, len = this.length; i < len; i++){
21128 * The parent node for this node. @type Node
21130 this.parentNode = null;
21132 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21134 this.firstChild = null;
21136 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21138 this.lastChild = null;
21140 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21142 this.previousSibling = null;
21144 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21146 this.nextSibling = null;
21151 * Fires when a new child node is appended
21152 * @param {Tree} tree The owner tree
21153 * @param {Node} this This node
21154 * @param {Node} node The newly appended node
21155 * @param {Number} index The index of the newly appended node
21160 * Fires when a child node is removed
21161 * @param {Tree} tree The owner tree
21162 * @param {Node} this This node
21163 * @param {Node} node The removed node
21168 * Fires when this node is moved to a new location in the tree
21169 * @param {Tree} tree The owner tree
21170 * @param {Node} this This node
21171 * @param {Node} oldParent The old parent of this node
21172 * @param {Node} newParent The new parent of this node
21173 * @param {Number} index The index it was moved to
21178 * Fires when a new child node is inserted.
21179 * @param {Tree} tree The owner tree
21180 * @param {Node} this This node
21181 * @param {Node} node The child node inserted
21182 * @param {Node} refNode The child node the node was inserted before
21186 * @event beforeappend
21187 * Fires before a new child is appended, return false to cancel the append.
21188 * @param {Tree} tree The owner tree
21189 * @param {Node} this This node
21190 * @param {Node} node The child node to be appended
21192 "beforeappend" : true,
21194 * @event beforeremove
21195 * Fires before a child is removed, return false to cancel the remove.
21196 * @param {Tree} tree The owner tree
21197 * @param {Node} this This node
21198 * @param {Node} node The child node to be removed
21200 "beforeremove" : true,
21202 * @event beforemove
21203 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21204 * @param {Tree} tree The owner tree
21205 * @param {Node} this This node
21206 * @param {Node} oldParent The parent of this node
21207 * @param {Node} newParent The new parent this node is moving to
21208 * @param {Number} index The index it is being moved to
21210 "beforemove" : true,
21212 * @event beforeinsert
21213 * Fires before a new child is inserted, return false to cancel the insert.
21214 * @param {Tree} tree The owner tree
21215 * @param {Node} this This node
21216 * @param {Node} node The child node to be inserted
21217 * @param {Node} refNode The child node the node is being inserted before
21219 "beforeinsert" : true
21221 this.listeners = this.attributes.listeners;
21222 Roo.data.Node.superclass.constructor.call(this);
21225 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21226 fireEvent : function(evtName){
21227 // first do standard event for this node
21228 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21231 // then bubble it up to the tree if the event wasn't cancelled
21232 var ot = this.getOwnerTree();
21234 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21242 * Returns true if this node is a leaf
21243 * @return {Boolean}
21245 isLeaf : function(){
21246 return this.leaf === true;
21250 setFirstChild : function(node){
21251 this.firstChild = node;
21255 setLastChild : function(node){
21256 this.lastChild = node;
21261 * Returns true if this node is the last child of its parent
21262 * @return {Boolean}
21264 isLast : function(){
21265 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21269 * Returns true if this node is the first child of its parent
21270 * @return {Boolean}
21272 isFirst : function(){
21273 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21276 hasChildNodes : function(){
21277 return !this.isLeaf() && this.childNodes.length > 0;
21281 * Insert node(s) as the last child node of this node.
21282 * @param {Node/Array} node The node or Array of nodes to append
21283 * @return {Node} The appended node if single append, or null if an array was passed
21285 appendChild : function(node){
21287 if(node instanceof Array){
21289 }else if(arguments.length > 1){
21292 // if passed an array or multiple args do them one by one
21294 for(var i = 0, len = multi.length; i < len; i++) {
21295 this.appendChild(multi[i]);
21298 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21301 var index = this.childNodes.length;
21302 var oldParent = node.parentNode;
21303 // it's a move, make sure we move it cleanly
21305 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21308 oldParent.removeChild(node);
21310 index = this.childNodes.length;
21312 this.setFirstChild(node);
21314 this.childNodes.push(node);
21315 node.parentNode = this;
21316 var ps = this.childNodes[index-1];
21318 node.previousSibling = ps;
21319 ps.nextSibling = node;
21321 node.previousSibling = null;
21323 node.nextSibling = null;
21324 this.setLastChild(node);
21325 node.setOwnerTree(this.getOwnerTree());
21326 this.fireEvent("append", this.ownerTree, this, node, index);
21328 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21335 * Removes a child node from this node.
21336 * @param {Node} node The node to remove
21337 * @return {Node} The removed node
21339 removeChild : function(node){
21340 var index = this.childNodes.indexOf(node);
21344 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21348 // remove it from childNodes collection
21349 this.childNodes.splice(index, 1);
21352 if(node.previousSibling){
21353 node.previousSibling.nextSibling = node.nextSibling;
21355 if(node.nextSibling){
21356 node.nextSibling.previousSibling = node.previousSibling;
21359 // update child refs
21360 if(this.firstChild == node){
21361 this.setFirstChild(node.nextSibling);
21363 if(this.lastChild == node){
21364 this.setLastChild(node.previousSibling);
21367 node.setOwnerTree(null);
21368 // clear any references from the node
21369 node.parentNode = null;
21370 node.previousSibling = null;
21371 node.nextSibling = null;
21372 this.fireEvent("remove", this.ownerTree, this, node);
21377 * Inserts the first node before the second node in this nodes childNodes collection.
21378 * @param {Node} node The node to insert
21379 * @param {Node} refNode The node to insert before (if null the node is appended)
21380 * @return {Node} The inserted node
21382 insertBefore : function(node, refNode){
21383 if(!refNode){ // like standard Dom, refNode can be null for append
21384 return this.appendChild(node);
21387 if(node == refNode){
21391 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21394 var index = this.childNodes.indexOf(refNode);
21395 var oldParent = node.parentNode;
21396 var refIndex = index;
21398 // when moving internally, indexes will change after remove
21399 if(oldParent == this && this.childNodes.indexOf(node) < index){
21403 // it's a move, make sure we move it cleanly
21405 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21408 oldParent.removeChild(node);
21411 this.setFirstChild(node);
21413 this.childNodes.splice(refIndex, 0, node);
21414 node.parentNode = this;
21415 var ps = this.childNodes[refIndex-1];
21417 node.previousSibling = ps;
21418 ps.nextSibling = node;
21420 node.previousSibling = null;
21422 node.nextSibling = refNode;
21423 refNode.previousSibling = node;
21424 node.setOwnerTree(this.getOwnerTree());
21425 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21427 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21433 * Returns the child node at the specified index.
21434 * @param {Number} index
21437 item : function(index){
21438 return this.childNodes[index];
21442 * Replaces one child node in this node with another.
21443 * @param {Node} newChild The replacement node
21444 * @param {Node} oldChild The node to replace
21445 * @return {Node} The replaced node
21447 replaceChild : function(newChild, oldChild){
21448 this.insertBefore(newChild, oldChild);
21449 this.removeChild(oldChild);
21454 * Returns the index of a child node
21455 * @param {Node} node
21456 * @return {Number} The index of the node or -1 if it was not found
21458 indexOf : function(child){
21459 return this.childNodes.indexOf(child);
21463 * Returns the tree this node is in.
21466 getOwnerTree : function(){
21467 // if it doesn't have one, look for one
21468 if(!this.ownerTree){
21472 this.ownerTree = p.ownerTree;
21478 return this.ownerTree;
21482 * Returns depth of this node (the root node has a depth of 0)
21485 getDepth : function(){
21488 while(p.parentNode){
21496 setOwnerTree : function(tree){
21497 // if it's move, we need to update everyone
21498 if(tree != this.ownerTree){
21499 if(this.ownerTree){
21500 this.ownerTree.unregisterNode(this);
21502 this.ownerTree = tree;
21503 var cs = this.childNodes;
21504 for(var i = 0, len = cs.length; i < len; i++) {
21505 cs[i].setOwnerTree(tree);
21508 tree.registerNode(this);
21514 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21515 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21516 * @return {String} The path
21518 getPath : function(attr){
21519 attr = attr || "id";
21520 var p = this.parentNode;
21521 var b = [this.attributes[attr]];
21523 b.unshift(p.attributes[attr]);
21526 var sep = this.getOwnerTree().pathSeparator;
21527 return sep + b.join(sep);
21531 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21532 * function call will be the scope provided or the current node. The arguments to the function
21533 * will be the args provided or the current node. If the function returns false at any point,
21534 * the bubble is stopped.
21535 * @param {Function} fn The function to call
21536 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21537 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21539 bubble : function(fn, scope, args){
21542 if(fn.call(scope || p, args || p) === false){
21550 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21551 * function call will be the scope provided or the current node. The arguments to the function
21552 * will be the args provided or the current node. If the function returns false at any point,
21553 * the cascade is stopped on that branch.
21554 * @param {Function} fn The function to call
21555 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21556 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21558 cascade : function(fn, scope, args){
21559 if(fn.call(scope || this, args || this) !== false){
21560 var cs = this.childNodes;
21561 for(var i = 0, len = cs.length; i < len; i++) {
21562 cs[i].cascade(fn, scope, args);
21568 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21569 * function call will be the scope provided or the current node. The arguments to the function
21570 * will be the args provided or the current node. If the function returns false at any point,
21571 * the iteration stops.
21572 * @param {Function} fn The function to call
21573 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21574 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21576 eachChild : function(fn, scope, args){
21577 var cs = this.childNodes;
21578 for(var i = 0, len = cs.length; i < len; i++) {
21579 if(fn.call(scope || this, args || cs[i]) === false){
21586 * Finds the first child that has the attribute with the specified value.
21587 * @param {String} attribute The attribute name
21588 * @param {Mixed} value The value to search for
21589 * @return {Node} The found child or null if none was found
21591 findChild : function(attribute, value){
21592 var cs = this.childNodes;
21593 for(var i = 0, len = cs.length; i < len; i++) {
21594 if(cs[i].attributes[attribute] == value){
21602 * Finds the first child by a custom function. The child matches if the function passed
21604 * @param {Function} fn
21605 * @param {Object} scope (optional)
21606 * @return {Node} The found child or null if none was found
21608 findChildBy : function(fn, scope){
21609 var cs = this.childNodes;
21610 for(var i = 0, len = cs.length; i < len; i++) {
21611 if(fn.call(scope||cs[i], cs[i]) === true){
21619 * Sorts this nodes children using the supplied sort function
21620 * @param {Function} fn
21621 * @param {Object} scope (optional)
21623 sort : function(fn, scope){
21624 var cs = this.childNodes;
21625 var len = cs.length;
21627 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21629 for(var i = 0; i < len; i++){
21631 n.previousSibling = cs[i-1];
21632 n.nextSibling = cs[i+1];
21634 this.setFirstChild(n);
21637 this.setLastChild(n);
21644 * Returns true if this node is an ancestor (at any point) of the passed node.
21645 * @param {Node} node
21646 * @return {Boolean}
21648 contains : function(node){
21649 return node.isAncestor(this);
21653 * Returns true if the passed node is an ancestor (at any point) of this node.
21654 * @param {Node} node
21655 * @return {Boolean}
21657 isAncestor : function(node){
21658 var p = this.parentNode;
21668 toString : function(){
21669 return "[Node"+(this.id?" "+this.id:"")+"]";
21673 * Ext JS Library 1.1.1
21674 * Copyright(c) 2006-2007, Ext JS, LLC.
21676 * Originally Released Under LGPL - original licence link has changed is not relivant.
21679 * <script type="text/javascript">
21684 * @class Roo.ComponentMgr
21685 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21688 Roo.ComponentMgr = function(){
21689 var all = new Roo.util.MixedCollection();
21693 * Registers a component.
21694 * @param {Roo.Component} c The component
21696 register : function(c){
21701 * Unregisters a component.
21702 * @param {Roo.Component} c The component
21704 unregister : function(c){
21709 * Returns a component by id
21710 * @param {String} id The component id
21712 get : function(id){
21713 return all.get(id);
21717 * Registers a function that will be called when a specified component is added to ComponentMgr
21718 * @param {String} id The component id
21719 * @param {Funtction} fn The callback function
21720 * @param {Object} scope The scope of the callback
21722 onAvailable : function(id, fn, scope){
21723 all.on("add", function(index, o){
21725 fn.call(scope || o, o);
21726 all.un("add", fn, scope);
21733 * Ext JS Library 1.1.1
21734 * Copyright(c) 2006-2007, Ext JS, LLC.
21736 * Originally Released Under LGPL - original licence link has changed is not relivant.
21739 * <script type="text/javascript">
21743 * @class Roo.Component
21744 * @extends Roo.util.Observable
21745 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21746 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21747 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21748 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21749 * All visual components (widgets) that require rendering into a layout should subclass Component.
21751 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21752 * 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
21753 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21755 Roo.Component = function(config){
21756 config = config || {};
21757 if(config.tagName || config.dom || typeof config == "string"){ // element object
21758 config = {el: config, id: config.id || config};
21760 this.initialConfig = config;
21762 Roo.apply(this, config);
21766 * Fires after the component is disabled.
21767 * @param {Roo.Component} this
21772 * Fires after the component is enabled.
21773 * @param {Roo.Component} this
21777 * @event beforeshow
21778 * Fires before the component is shown. Return false to stop the show.
21779 * @param {Roo.Component} this
21784 * Fires after the component is shown.
21785 * @param {Roo.Component} this
21789 * @event beforehide
21790 * Fires before the component is hidden. Return false to stop the hide.
21791 * @param {Roo.Component} this
21796 * Fires after the component is hidden.
21797 * @param {Roo.Component} this
21801 * @event beforerender
21802 * Fires before the component is rendered. Return false to stop the render.
21803 * @param {Roo.Component} this
21805 beforerender : true,
21808 * Fires after the component is rendered.
21809 * @param {Roo.Component} this
21813 * @event beforedestroy
21814 * Fires before the component is destroyed. Return false to stop the destroy.
21815 * @param {Roo.Component} this
21817 beforedestroy : true,
21820 * Fires after the component is destroyed.
21821 * @param {Roo.Component} this
21826 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21828 Roo.ComponentMgr.register(this);
21829 Roo.Component.superclass.constructor.call(this);
21830 this.initComponent();
21831 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21832 this.render(this.renderTo);
21833 delete this.renderTo;
21838 Roo.Component.AUTO_ID = 1000;
21840 Roo.extend(Roo.Component, Roo.util.Observable, {
21842 * @property {Boolean} hidden
21843 * true if this component is hidden. Read-only.
21847 * true if this component is disabled. Read-only.
21851 * true if this component has been rendered. Read-only.
21855 /** @cfg {String} disableClass
21856 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21858 disabledClass : "x-item-disabled",
21859 /** @cfg {Boolean} allowDomMove
21860 * Whether the component can move the Dom node when rendering (defaults to true).
21862 allowDomMove : true,
21863 /** @cfg {String} hideMode
21864 * How this component should hidden. Supported values are
21865 * "visibility" (css visibility), "offsets" (negative offset position) and
21866 * "display" (css display) - defaults to "display".
21868 hideMode: 'display',
21871 ctype : "Roo.Component",
21873 /** @cfg {String} actionMode
21874 * which property holds the element that used for hide() / show() / disable() / enable()
21880 getActionEl : function(){
21881 return this[this.actionMode];
21884 initComponent : Roo.emptyFn,
21886 * If this is a lazy rendering component, render it to its container element.
21887 * @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.
21889 render : function(container, position){
21890 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21891 if(!container && this.el){
21892 this.el = Roo.get(this.el);
21893 container = this.el.dom.parentNode;
21894 this.allowDomMove = false;
21896 this.container = Roo.get(container);
21897 this.rendered = true;
21898 if(position !== undefined){
21899 if(typeof position == 'number'){
21900 position = this.container.dom.childNodes[position];
21902 position = Roo.getDom(position);
21905 this.onRender(this.container, position || null);
21907 this.el.addClass(this.cls);
21911 this.el.applyStyles(this.style);
21914 this.fireEvent("render", this);
21915 this.afterRender(this.container);
21927 // default function is not really useful
21928 onRender : function(ct, position){
21930 this.el = Roo.get(this.el);
21931 if(this.allowDomMove !== false){
21932 ct.dom.insertBefore(this.el.dom, position);
21938 getAutoCreate : function(){
21939 var cfg = typeof this.autoCreate == "object" ?
21940 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21941 if(this.id && !cfg.id){
21948 afterRender : Roo.emptyFn,
21951 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21952 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21954 destroy : function(){
21955 if(this.fireEvent("beforedestroy", this) !== false){
21956 this.purgeListeners();
21957 this.beforeDestroy();
21959 this.el.removeAllListeners();
21961 if(this.actionMode == "container"){
21962 this.container.remove();
21966 Roo.ComponentMgr.unregister(this);
21967 this.fireEvent("destroy", this);
21972 beforeDestroy : function(){
21977 onDestroy : function(){
21982 * Returns the underlying {@link Roo.Element}.
21983 * @return {Roo.Element} The element
21985 getEl : function(){
21990 * Returns the id of this component.
21993 getId : function(){
21998 * Try to focus this component.
21999 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22000 * @return {Roo.Component} this
22002 focus : function(selectText){
22005 if(selectText === true){
22006 this.el.dom.select();
22021 * Disable this component.
22022 * @return {Roo.Component} this
22024 disable : function(){
22028 this.disabled = true;
22029 this.fireEvent("disable", this);
22034 onDisable : function(){
22035 this.getActionEl().addClass(this.disabledClass);
22036 this.el.dom.disabled = true;
22040 * Enable this component.
22041 * @return {Roo.Component} this
22043 enable : function(){
22047 this.disabled = false;
22048 this.fireEvent("enable", this);
22053 onEnable : function(){
22054 this.getActionEl().removeClass(this.disabledClass);
22055 this.el.dom.disabled = false;
22059 * Convenience function for setting disabled/enabled by boolean.
22060 * @param {Boolean} disabled
22062 setDisabled : function(disabled){
22063 this[disabled ? "disable" : "enable"]();
22067 * Show this component.
22068 * @return {Roo.Component} this
22071 if(this.fireEvent("beforeshow", this) !== false){
22072 this.hidden = false;
22076 this.fireEvent("show", this);
22082 onShow : function(){
22083 var ae = this.getActionEl();
22084 if(this.hideMode == 'visibility'){
22085 ae.dom.style.visibility = "visible";
22086 }else if(this.hideMode == 'offsets'){
22087 ae.removeClass('x-hidden');
22089 ae.dom.style.display = "";
22094 * Hide this component.
22095 * @return {Roo.Component} this
22098 if(this.fireEvent("beforehide", this) !== false){
22099 this.hidden = true;
22103 this.fireEvent("hide", this);
22109 onHide : function(){
22110 var ae = this.getActionEl();
22111 if(this.hideMode == 'visibility'){
22112 ae.dom.style.visibility = "hidden";
22113 }else if(this.hideMode == 'offsets'){
22114 ae.addClass('x-hidden');
22116 ae.dom.style.display = "none";
22121 * Convenience function to hide or show this component by boolean.
22122 * @param {Boolean} visible True to show, false to hide
22123 * @return {Roo.Component} this
22125 setVisible: function(visible){
22135 * Returns true if this component is visible.
22137 isVisible : function(){
22138 return this.getActionEl().isVisible();
22141 cloneConfig : function(overrides){
22142 overrides = overrides || {};
22143 var id = overrides.id || Roo.id();
22144 var cfg = Roo.applyIf(overrides, this.initialConfig);
22145 cfg.id = id; // prevent dup id
22146 return new this.constructor(cfg);
22150 * Ext JS Library 1.1.1
22151 * Copyright(c) 2006-2007, Ext JS, LLC.
22153 * Originally Released Under LGPL - original licence link has changed is not relivant.
22156 * <script type="text/javascript">
22161 * @extends Roo.Element
22162 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22163 * automatic maintaining of shadow/shim positions.
22164 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22165 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22166 * you can pass a string with a CSS class name. False turns off the shadow.
22167 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22168 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22169 * @cfg {String} cls CSS class to add to the element
22170 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22171 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22173 * @param {Object} config An object with config options.
22174 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22177 Roo.Layer = function(config, existingEl){
22178 config = config || {};
22179 var dh = Roo.DomHelper;
22180 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22182 this.dom = Roo.getDom(existingEl);
22185 var o = config.dh || {tag: "div", cls: "x-layer"};
22186 this.dom = dh.append(pel, o);
22189 this.addClass(config.cls);
22191 this.constrain = config.constrain !== false;
22192 this.visibilityMode = Roo.Element.VISIBILITY;
22194 this.id = this.dom.id = config.id;
22196 this.id = Roo.id(this.dom);
22198 this.zindex = config.zindex || this.getZIndex();
22199 this.position("absolute", this.zindex);
22201 this.shadowOffset = config.shadowOffset || 4;
22202 this.shadow = new Roo.Shadow({
22203 offset : this.shadowOffset,
22204 mode : config.shadow
22207 this.shadowOffset = 0;
22209 this.useShim = config.shim !== false && Roo.useShims;
22210 this.useDisplay = config.useDisplay;
22214 var supr = Roo.Element.prototype;
22216 // shims are shared among layer to keep from having 100 iframes
22219 Roo.extend(Roo.Layer, Roo.Element, {
22221 getZIndex : function(){
22222 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22225 getShim : function(){
22232 var shim = shims.shift();
22234 shim = this.createShim();
22235 shim.enableDisplayMode('block');
22236 shim.dom.style.display = 'none';
22237 shim.dom.style.visibility = 'visible';
22239 var pn = this.dom.parentNode;
22240 if(shim.dom.parentNode != pn){
22241 pn.insertBefore(shim.dom, this.dom);
22243 shim.setStyle('z-index', this.getZIndex()-2);
22248 hideShim : function(){
22250 this.shim.setDisplayed(false);
22251 shims.push(this.shim);
22256 disableShadow : function(){
22258 this.shadowDisabled = true;
22259 this.shadow.hide();
22260 this.lastShadowOffset = this.shadowOffset;
22261 this.shadowOffset = 0;
22265 enableShadow : function(show){
22267 this.shadowDisabled = false;
22268 this.shadowOffset = this.lastShadowOffset;
22269 delete this.lastShadowOffset;
22277 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22278 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22279 sync : function(doShow){
22280 var sw = this.shadow;
22281 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22282 var sh = this.getShim();
22284 var w = this.getWidth(),
22285 h = this.getHeight();
22287 var l = this.getLeft(true),
22288 t = this.getTop(true);
22290 if(sw && !this.shadowDisabled){
22291 if(doShow && !sw.isVisible()){
22294 sw.realign(l, t, w, h);
22300 // fit the shim behind the shadow, so it is shimmed too
22301 var a = sw.adjusts, s = sh.dom.style;
22302 s.left = (Math.min(l, l+a.l))+"px";
22303 s.top = (Math.min(t, t+a.t))+"px";
22304 s.width = (w+a.w)+"px";
22305 s.height = (h+a.h)+"px";
22312 sh.setLeftTop(l, t);
22319 destroy : function(){
22322 this.shadow.hide();
22324 this.removeAllListeners();
22325 var pn = this.dom.parentNode;
22327 pn.removeChild(this.dom);
22329 Roo.Element.uncache(this.id);
22332 remove : function(){
22337 beginUpdate : function(){
22338 this.updating = true;
22342 endUpdate : function(){
22343 this.updating = false;
22348 hideUnders : function(negOffset){
22350 this.shadow.hide();
22356 constrainXY : function(){
22357 if(this.constrain){
22358 var vw = Roo.lib.Dom.getViewWidth(),
22359 vh = Roo.lib.Dom.getViewHeight();
22360 var s = Roo.get(document).getScroll();
22362 var xy = this.getXY();
22363 var x = xy[0], y = xy[1];
22364 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22365 // only move it if it needs it
22367 // first validate right/bottom
22368 if((x + w) > vw+s.left){
22369 x = vw - w - this.shadowOffset;
22372 if((y + h) > vh+s.top){
22373 y = vh - h - this.shadowOffset;
22376 // then make sure top/left isn't negative
22387 var ay = this.avoidY;
22388 if(y <= ay && (y+h) >= ay){
22394 supr.setXY.call(this, xy);
22400 isVisible : function(){
22401 return this.visible;
22405 showAction : function(){
22406 this.visible = true; // track visibility to prevent getStyle calls
22407 if(this.useDisplay === true){
22408 this.setDisplayed("");
22409 }else if(this.lastXY){
22410 supr.setXY.call(this, this.lastXY);
22411 }else if(this.lastLT){
22412 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22417 hideAction : function(){
22418 this.visible = false;
22419 if(this.useDisplay === true){
22420 this.setDisplayed(false);
22422 this.setLeftTop(-10000,-10000);
22426 // overridden Element method
22427 setVisible : function(v, a, d, c, e){
22432 var cb = function(){
22437 }.createDelegate(this);
22438 supr.setVisible.call(this, true, true, d, cb, e);
22441 this.hideUnders(true);
22450 }.createDelegate(this);
22452 supr.setVisible.call(this, v, a, d, cb, e);
22461 storeXY : function(xy){
22462 delete this.lastLT;
22466 storeLeftTop : function(left, top){
22467 delete this.lastXY;
22468 this.lastLT = [left, top];
22472 beforeFx : function(){
22473 this.beforeAction();
22474 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22478 afterFx : function(){
22479 Roo.Layer.superclass.afterFx.apply(this, arguments);
22480 this.sync(this.isVisible());
22484 beforeAction : function(){
22485 if(!this.updating && this.shadow){
22486 this.shadow.hide();
22490 // overridden Element method
22491 setLeft : function(left){
22492 this.storeLeftTop(left, this.getTop(true));
22493 supr.setLeft.apply(this, arguments);
22497 setTop : function(top){
22498 this.storeLeftTop(this.getLeft(true), top);
22499 supr.setTop.apply(this, arguments);
22503 setLeftTop : function(left, top){
22504 this.storeLeftTop(left, top);
22505 supr.setLeftTop.apply(this, arguments);
22509 setXY : function(xy, a, d, c, e){
22511 this.beforeAction();
22513 var cb = this.createCB(c);
22514 supr.setXY.call(this, xy, a, d, cb, e);
22521 createCB : function(c){
22532 // overridden Element method
22533 setX : function(x, a, d, c, e){
22534 this.setXY([x, this.getY()], a, d, c, e);
22537 // overridden Element method
22538 setY : function(y, a, d, c, e){
22539 this.setXY([this.getX(), y], a, d, c, e);
22542 // overridden Element method
22543 setSize : function(w, h, a, d, c, e){
22544 this.beforeAction();
22545 var cb = this.createCB(c);
22546 supr.setSize.call(this, w, h, a, d, cb, e);
22552 // overridden Element method
22553 setWidth : function(w, a, d, c, e){
22554 this.beforeAction();
22555 var cb = this.createCB(c);
22556 supr.setWidth.call(this, w, a, d, cb, e);
22562 // overridden Element method
22563 setHeight : function(h, a, d, c, e){
22564 this.beforeAction();
22565 var cb = this.createCB(c);
22566 supr.setHeight.call(this, h, a, d, cb, e);
22572 // overridden Element method
22573 setBounds : function(x, y, w, h, a, d, c, e){
22574 this.beforeAction();
22575 var cb = this.createCB(c);
22577 this.storeXY([x, y]);
22578 supr.setXY.call(this, [x, y]);
22579 supr.setSize.call(this, w, h, a, d, cb, e);
22582 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22588 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22589 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22590 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22591 * @param {Number} zindex The new z-index to set
22592 * @return {this} The Layer
22594 setZIndex : function(zindex){
22595 this.zindex = zindex;
22596 this.setStyle("z-index", zindex + 2);
22598 this.shadow.setZIndex(zindex + 1);
22601 this.shim.setStyle("z-index", zindex);
22607 * Ext JS Library 1.1.1
22608 * Copyright(c) 2006-2007, Ext JS, LLC.
22610 * Originally Released Under LGPL - original licence link has changed is not relivant.
22613 * <script type="text/javascript">
22618 * @class Roo.Shadow
22619 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22620 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22621 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22623 * Create a new Shadow
22624 * @param {Object} config The config object
22626 Roo.Shadow = function(config){
22627 Roo.apply(this, config);
22628 if(typeof this.mode != "string"){
22629 this.mode = this.defaultMode;
22631 var o = this.offset, a = {h: 0};
22632 var rad = Math.floor(this.offset/2);
22633 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22639 a.l -= this.offset + rad;
22640 a.t -= this.offset + rad;
22651 a.l -= (this.offset - rad);
22652 a.t -= this.offset + rad;
22654 a.w -= (this.offset - rad)*2;
22665 a.l -= (this.offset - rad);
22666 a.t -= (this.offset - rad);
22668 a.w -= (this.offset + rad + 1);
22669 a.h -= (this.offset + rad);
22678 Roo.Shadow.prototype = {
22680 * @cfg {String} mode
22681 * The shadow display mode. Supports the following options:<br />
22682 * sides: Shadow displays on both sides and bottom only<br />
22683 * frame: Shadow displays equally on all four sides<br />
22684 * drop: Traditional bottom-right drop shadow (default)
22687 * @cfg {String} offset
22688 * The number of pixels to offset the shadow from the element (defaults to 4)
22693 defaultMode: "drop",
22696 * Displays the shadow under the target element
22697 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22699 show : function(target){
22700 target = Roo.get(target);
22702 this.el = Roo.Shadow.Pool.pull();
22703 if(this.el.dom.nextSibling != target.dom){
22704 this.el.insertBefore(target);
22707 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22709 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22712 target.getLeft(true),
22713 target.getTop(true),
22717 this.el.dom.style.display = "block";
22721 * Returns true if the shadow is visible, else false
22723 isVisible : function(){
22724 return this.el ? true : false;
22728 * Direct alignment when values are already available. Show must be called at least once before
22729 * calling this method to ensure it is initialized.
22730 * @param {Number} left The target element left position
22731 * @param {Number} top The target element top position
22732 * @param {Number} width The target element width
22733 * @param {Number} height The target element height
22735 realign : function(l, t, w, h){
22739 var a = this.adjusts, d = this.el.dom, s = d.style;
22741 s.left = (l+a.l)+"px";
22742 s.top = (t+a.t)+"px";
22743 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22745 if(s.width != sws || s.height != shs){
22749 var cn = d.childNodes;
22750 var sww = Math.max(0, (sw-12))+"px";
22751 cn[0].childNodes[1].style.width = sww;
22752 cn[1].childNodes[1].style.width = sww;
22753 cn[2].childNodes[1].style.width = sww;
22754 cn[1].style.height = Math.max(0, (sh-12))+"px";
22760 * Hides this shadow
22764 this.el.dom.style.display = "none";
22765 Roo.Shadow.Pool.push(this.el);
22771 * Adjust the z-index of this shadow
22772 * @param {Number} zindex The new z-index
22774 setZIndex : function(z){
22777 this.el.setStyle("z-index", z);
22782 // Private utility class that manages the internal Shadow cache
22783 Roo.Shadow.Pool = function(){
22785 var markup = Roo.isIE ?
22786 '<div class="x-ie-shadow"></div>' :
22787 '<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>';
22790 var sh = p.shift();
22792 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22793 sh.autoBoxAdjust = false;
22798 push : function(sh){
22804 * Ext JS Library 1.1.1
22805 * Copyright(c) 2006-2007, Ext JS, LLC.
22807 * Originally Released Under LGPL - original licence link has changed is not relivant.
22810 * <script type="text/javascript">
22814 * @class Roo.BoxComponent
22815 * @extends Roo.Component
22816 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22817 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22818 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22819 * layout containers.
22821 * @param {Roo.Element/String/Object} config The configuration options.
22823 Roo.BoxComponent = function(config){
22824 Roo.Component.call(this, config);
22828 * Fires after the component is resized.
22829 * @param {Roo.Component} this
22830 * @param {Number} adjWidth The box-adjusted width that was set
22831 * @param {Number} adjHeight The box-adjusted height that was set
22832 * @param {Number} rawWidth The width that was originally specified
22833 * @param {Number} rawHeight The height that was originally specified
22838 * Fires after the component is moved.
22839 * @param {Roo.Component} this
22840 * @param {Number} x The new x position
22841 * @param {Number} y The new y position
22847 Roo.extend(Roo.BoxComponent, Roo.Component, {
22848 // private, set in afterRender to signify that the component has been rendered
22850 // private, used to defer height settings to subclasses
22851 deferHeight: false,
22852 /** @cfg {Number} width
22853 * width (optional) size of component
22855 /** @cfg {Number} height
22856 * height (optional) size of component
22860 * Sets the width and height of the component. This method fires the resize event. This method can accept
22861 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22862 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22863 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22864 * @return {Roo.BoxComponent} this
22866 setSize : function(w, h){
22867 // support for standard size objects
22868 if(typeof w == 'object'){
22873 if(!this.boxReady){
22879 // prevent recalcs when not needed
22880 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22883 this.lastSize = {width: w, height: h};
22885 var adj = this.adjustSize(w, h);
22886 var aw = adj.width, ah = adj.height;
22887 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22888 var rz = this.getResizeEl();
22889 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22890 rz.setSize(aw, ah);
22891 }else if(!this.deferHeight && ah !== undefined){
22893 }else if(aw !== undefined){
22896 this.onResize(aw, ah, w, h);
22897 this.fireEvent('resize', this, aw, ah, w, h);
22903 * Gets the current size of the component's underlying element.
22904 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22906 getSize : function(){
22907 return this.el.getSize();
22911 * Gets the current XY position of the component's underlying element.
22912 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22913 * @return {Array} The XY position of the element (e.g., [100, 200])
22915 getPosition : function(local){
22916 if(local === true){
22917 return [this.el.getLeft(true), this.el.getTop(true)];
22919 return this.xy || this.el.getXY();
22923 * Gets the current box measurements of the component's underlying element.
22924 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22925 * @returns {Object} box An object in the format {x, y, width, height}
22927 getBox : function(local){
22928 var s = this.el.getSize();
22930 s.x = this.el.getLeft(true);
22931 s.y = this.el.getTop(true);
22933 var xy = this.xy || this.el.getXY();
22941 * Sets the current box measurements of the component's underlying element.
22942 * @param {Object} box An object in the format {x, y, width, height}
22943 * @returns {Roo.BoxComponent} this
22945 updateBox : function(box){
22946 this.setSize(box.width, box.height);
22947 this.setPagePosition(box.x, box.y);
22952 getResizeEl : function(){
22953 return this.resizeEl || this.el;
22957 getPositionEl : function(){
22958 return this.positionEl || this.el;
22962 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22963 * This method fires the move event.
22964 * @param {Number} left The new left
22965 * @param {Number} top The new top
22966 * @returns {Roo.BoxComponent} this
22968 setPosition : function(x, y){
22971 if(!this.boxReady){
22974 var adj = this.adjustPosition(x, y);
22975 var ax = adj.x, ay = adj.y;
22977 var el = this.getPositionEl();
22978 if(ax !== undefined || ay !== undefined){
22979 if(ax !== undefined && ay !== undefined){
22980 el.setLeftTop(ax, ay);
22981 }else if(ax !== undefined){
22983 }else if(ay !== undefined){
22986 this.onPosition(ax, ay);
22987 this.fireEvent('move', this, ax, ay);
22993 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22994 * This method fires the move event.
22995 * @param {Number} x The new x position
22996 * @param {Number} y The new y position
22997 * @returns {Roo.BoxComponent} this
22999 setPagePosition : function(x, y){
23002 if(!this.boxReady){
23005 if(x === undefined || y === undefined){ // cannot translate undefined points
23008 var p = this.el.translatePoints(x, y);
23009 this.setPosition(p.left, p.top);
23014 onRender : function(ct, position){
23015 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23017 this.resizeEl = Roo.get(this.resizeEl);
23019 if(this.positionEl){
23020 this.positionEl = Roo.get(this.positionEl);
23025 afterRender : function(){
23026 Roo.BoxComponent.superclass.afterRender.call(this);
23027 this.boxReady = true;
23028 this.setSize(this.width, this.height);
23029 if(this.x || this.y){
23030 this.setPosition(this.x, this.y);
23032 if(this.pageX || this.pageY){
23033 this.setPagePosition(this.pageX, this.pageY);
23038 * Force the component's size to recalculate based on the underlying element's current height and width.
23039 * @returns {Roo.BoxComponent} this
23041 syncSize : function(){
23042 delete this.lastSize;
23043 this.setSize(this.el.getWidth(), this.el.getHeight());
23048 * Called after the component is resized, this method is empty by default but can be implemented by any
23049 * subclass that needs to perform custom logic after a resize occurs.
23050 * @param {Number} adjWidth The box-adjusted width that was set
23051 * @param {Number} adjHeight The box-adjusted height that was set
23052 * @param {Number} rawWidth The width that was originally specified
23053 * @param {Number} rawHeight The height that was originally specified
23055 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23060 * Called after the component is moved, this method is empty by default but can be implemented by any
23061 * subclass that needs to perform custom logic after a move occurs.
23062 * @param {Number} x The new x position
23063 * @param {Number} y The new y position
23065 onPosition : function(x, y){
23070 adjustSize : function(w, h){
23071 if(this.autoWidth){
23074 if(this.autoHeight){
23077 return {width : w, height: h};
23081 adjustPosition : function(x, y){
23082 return {x : x, y: y};
23086 * Ext JS Library 1.1.1
23087 * Copyright(c) 2006-2007, Ext JS, LLC.
23089 * Originally Released Under LGPL - original licence link has changed is not relivant.
23092 * <script type="text/javascript">
23097 * @class Roo.SplitBar
23098 * @extends Roo.util.Observable
23099 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23103 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23104 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23105 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23106 split.minSize = 100;
23107 split.maxSize = 600;
23108 split.animate = true;
23109 split.on('moved', splitterMoved);
23112 * Create a new SplitBar
23113 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23114 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23115 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23116 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23117 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23118 position of the SplitBar).
23120 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23123 this.el = Roo.get(dragElement, true);
23124 this.el.dom.unselectable = "on";
23126 this.resizingEl = Roo.get(resizingElement, true);
23130 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23131 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23134 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23137 * The minimum size of the resizing element. (Defaults to 0)
23143 * The maximum size of the resizing element. (Defaults to 2000)
23146 this.maxSize = 2000;
23149 * Whether to animate the transition to the new size
23152 this.animate = false;
23155 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23158 this.useShim = false;
23163 if(!existingProxy){
23165 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23167 this.proxy = Roo.get(existingProxy).dom;
23170 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23173 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23176 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23179 this.dragSpecs = {};
23182 * @private The adapter to use to positon and resize elements
23184 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23185 this.adapter.init(this);
23187 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23189 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23190 this.el.addClass("x-splitbar-h");
23193 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23194 this.el.addClass("x-splitbar-v");
23200 * Fires when the splitter is moved (alias for {@link #event-moved})
23201 * @param {Roo.SplitBar} this
23202 * @param {Number} newSize the new width or height
23207 * Fires when the splitter is moved
23208 * @param {Roo.SplitBar} this
23209 * @param {Number} newSize the new width or height
23213 * @event beforeresize
23214 * Fires before the splitter is dragged
23215 * @param {Roo.SplitBar} this
23217 "beforeresize" : true,
23219 "beforeapply" : true
23222 Roo.util.Observable.call(this);
23225 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23226 onStartProxyDrag : function(x, y){
23227 this.fireEvent("beforeresize", this);
23229 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23231 o.enableDisplayMode("block");
23232 // all splitbars share the same overlay
23233 Roo.SplitBar.prototype.overlay = o;
23235 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23236 this.overlay.show();
23237 Roo.get(this.proxy).setDisplayed("block");
23238 var size = this.adapter.getElementSize(this);
23239 this.activeMinSize = this.getMinimumSize();;
23240 this.activeMaxSize = this.getMaximumSize();;
23241 var c1 = size - this.activeMinSize;
23242 var c2 = Math.max(this.activeMaxSize - size, 0);
23243 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23244 this.dd.resetConstraints();
23245 this.dd.setXConstraint(
23246 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23247 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23249 this.dd.setYConstraint(0, 0);
23251 this.dd.resetConstraints();
23252 this.dd.setXConstraint(0, 0);
23253 this.dd.setYConstraint(
23254 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23255 this.placement == Roo.SplitBar.TOP ? c2 : c1
23258 this.dragSpecs.startSize = size;
23259 this.dragSpecs.startPoint = [x, y];
23260 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23264 * @private Called after the drag operation by the DDProxy
23266 onEndProxyDrag : function(e){
23267 Roo.get(this.proxy).setDisplayed(false);
23268 var endPoint = Roo.lib.Event.getXY(e);
23270 this.overlay.hide();
23273 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23274 newSize = this.dragSpecs.startSize +
23275 (this.placement == Roo.SplitBar.LEFT ?
23276 endPoint[0] - this.dragSpecs.startPoint[0] :
23277 this.dragSpecs.startPoint[0] - endPoint[0]
23280 newSize = this.dragSpecs.startSize +
23281 (this.placement == Roo.SplitBar.TOP ?
23282 endPoint[1] - this.dragSpecs.startPoint[1] :
23283 this.dragSpecs.startPoint[1] - endPoint[1]
23286 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23287 if(newSize != this.dragSpecs.startSize){
23288 if(this.fireEvent('beforeapply', this, newSize) !== false){
23289 this.adapter.setElementSize(this, newSize);
23290 this.fireEvent("moved", this, newSize);
23291 this.fireEvent("resize", this, newSize);
23297 * Get the adapter this SplitBar uses
23298 * @return The adapter object
23300 getAdapter : function(){
23301 return this.adapter;
23305 * Set the adapter this SplitBar uses
23306 * @param {Object} adapter A SplitBar adapter object
23308 setAdapter : function(adapter){
23309 this.adapter = adapter;
23310 this.adapter.init(this);
23314 * Gets the minimum size for the resizing element
23315 * @return {Number} The minimum size
23317 getMinimumSize : function(){
23318 return this.minSize;
23322 * Sets the minimum size for the resizing element
23323 * @param {Number} minSize The minimum size
23325 setMinimumSize : function(minSize){
23326 this.minSize = minSize;
23330 * Gets the maximum size for the resizing element
23331 * @return {Number} The maximum size
23333 getMaximumSize : function(){
23334 return this.maxSize;
23338 * Sets the maximum size for the resizing element
23339 * @param {Number} maxSize The maximum size
23341 setMaximumSize : function(maxSize){
23342 this.maxSize = maxSize;
23346 * Sets the initialize size for the resizing element
23347 * @param {Number} size The initial size
23349 setCurrentSize : function(size){
23350 var oldAnimate = this.animate;
23351 this.animate = false;
23352 this.adapter.setElementSize(this, size);
23353 this.animate = oldAnimate;
23357 * Destroy this splitbar.
23358 * @param {Boolean} removeEl True to remove the element
23360 destroy : function(removeEl){
23362 this.shim.remove();
23365 this.proxy.parentNode.removeChild(this.proxy);
23373 * @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.
23375 Roo.SplitBar.createProxy = function(dir){
23376 var proxy = new Roo.Element(document.createElement("div"));
23377 proxy.unselectable();
23378 var cls = 'x-splitbar-proxy';
23379 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23380 document.body.appendChild(proxy.dom);
23385 * @class Roo.SplitBar.BasicLayoutAdapter
23386 * Default Adapter. It assumes the splitter and resizing element are not positioned
23387 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23389 Roo.SplitBar.BasicLayoutAdapter = function(){
23392 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23393 // do nothing for now
23394 init : function(s){
23398 * Called before drag operations to get the current size of the resizing element.
23399 * @param {Roo.SplitBar} s The SplitBar using this adapter
23401 getElementSize : function(s){
23402 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23403 return s.resizingEl.getWidth();
23405 return s.resizingEl.getHeight();
23410 * Called after drag operations to set the size of the resizing element.
23411 * @param {Roo.SplitBar} s The SplitBar using this adapter
23412 * @param {Number} newSize The new size to set
23413 * @param {Function} onComplete A function to be invoked when resizing is complete
23415 setElementSize : function(s, newSize, onComplete){
23416 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23418 s.resizingEl.setWidth(newSize);
23420 onComplete(s, newSize);
23423 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23428 s.resizingEl.setHeight(newSize);
23430 onComplete(s, newSize);
23433 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23440 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23441 * @extends Roo.SplitBar.BasicLayoutAdapter
23442 * Adapter that moves the splitter element to align with the resized sizing element.
23443 * Used with an absolute positioned SplitBar.
23444 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23445 * document.body, make sure you assign an id to the body element.
23447 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23448 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23449 this.container = Roo.get(container);
23452 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23453 init : function(s){
23454 this.basic.init(s);
23457 getElementSize : function(s){
23458 return this.basic.getElementSize(s);
23461 setElementSize : function(s, newSize, onComplete){
23462 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23465 moveSplitter : function(s){
23466 var yes = Roo.SplitBar;
23467 switch(s.placement){
23469 s.el.setX(s.resizingEl.getRight());
23472 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23475 s.el.setY(s.resizingEl.getBottom());
23478 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23485 * Orientation constant - Create a vertical SplitBar
23489 Roo.SplitBar.VERTICAL = 1;
23492 * Orientation constant - Create a horizontal SplitBar
23496 Roo.SplitBar.HORIZONTAL = 2;
23499 * Placement constant - The resizing element is to the left of the splitter element
23503 Roo.SplitBar.LEFT = 1;
23506 * Placement constant - The resizing element is to the right of the splitter element
23510 Roo.SplitBar.RIGHT = 2;
23513 * Placement constant - The resizing element is positioned above the splitter element
23517 Roo.SplitBar.TOP = 3;
23520 * Placement constant - The resizing element is positioned under splitter element
23524 Roo.SplitBar.BOTTOM = 4;
23527 * Ext JS Library 1.1.1
23528 * Copyright(c) 2006-2007, Ext JS, LLC.
23530 * Originally Released Under LGPL - original licence link has changed is not relivant.
23533 * <script type="text/javascript">
23538 * @extends Roo.util.Observable
23539 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23540 * This class also supports single and multi selection modes. <br>
23541 * Create a data model bound view:
23543 var store = new Roo.data.Store(...);
23545 var view = new Roo.View({
23547 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23549 singleSelect: true,
23550 selectedClass: "ydataview-selected",
23554 // listen for node click?
23555 view.on("click", function(vw, index, node, e){
23556 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23560 dataModel.load("foobar.xml");
23562 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23564 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23565 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23567 * Note: old style constructor is still suported (container, template, config)
23570 * Create a new View
23571 * @param {Object} config The config object
23574 Roo.View = function(config, depreciated_tpl, depreciated_config){
23576 if (typeof(depreciated_tpl) == 'undefined') {
23577 // new way.. - universal constructor.
23578 Roo.apply(this, config);
23579 this.el = Roo.get(this.el);
23582 this.el = Roo.get(config);
23583 this.tpl = depreciated_tpl;
23584 Roo.apply(this, depreciated_config);
23588 if(typeof(this.tpl) == "string"){
23589 this.tpl = new Roo.Template(this.tpl);
23591 // support xtype ctors..
23592 this.tpl = new Roo.factory(this.tpl, Roo);
23596 this.tpl.compile();
23603 * @event beforeclick
23604 * Fires before a click is processed. Returns false to cancel the default action.
23605 * @param {Roo.View} this
23606 * @param {Number} index The index of the target node
23607 * @param {HTMLElement} node The target node
23608 * @param {Roo.EventObject} e The raw event object
23610 "beforeclick" : true,
23613 * Fires when a template node is clicked.
23614 * @param {Roo.View} this
23615 * @param {Number} index The index of the target node
23616 * @param {HTMLElement} node The target node
23617 * @param {Roo.EventObject} e The raw event object
23622 * Fires when a template node is double clicked.
23623 * @param {Roo.View} this
23624 * @param {Number} index The index of the target node
23625 * @param {HTMLElement} node The target node
23626 * @param {Roo.EventObject} e The raw event object
23630 * @event contextmenu
23631 * Fires when a template node is right clicked.
23632 * @param {Roo.View} this
23633 * @param {Number} index The index of the target node
23634 * @param {HTMLElement} node The target node
23635 * @param {Roo.EventObject} e The raw event object
23637 "contextmenu" : true,
23639 * @event selectionchange
23640 * Fires when the selected nodes change.
23641 * @param {Roo.View} this
23642 * @param {Array} selections Array of the selected nodes
23644 "selectionchange" : true,
23647 * @event beforeselect
23648 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23649 * @param {Roo.View} this
23650 * @param {HTMLElement} node The node to be selected
23651 * @param {Array} selections Array of currently selected nodes
23653 "beforeselect" : true
23657 "click": this.onClick,
23658 "dblclick": this.onDblClick,
23659 "contextmenu": this.onContextMenu,
23663 this.selections = [];
23665 this.cmp = new Roo.CompositeElementLite([]);
23667 this.store = Roo.factory(this.store, Roo.data);
23668 this.setStore(this.store, true);
23670 Roo.View.superclass.constructor.call(this);
23673 Roo.extend(Roo.View, Roo.util.Observable, {
23676 * @cfg {Roo.data.Store} store Data store to load data from.
23681 * @cfg {String|Roo.Element} el The container element.
23686 * @cfg {String|Roo.Template} tpl The template used by this View
23691 * @cfg {String} selectedClass The css class to add to selected nodes
23693 selectedClass : "x-view-selected",
23695 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23699 * @cfg {Boolean} multiSelect Allow multiple selection
23702 multiSelect : false,
23704 * @cfg {Boolean} singleSelect Allow single selection
23706 singleSelect: false,
23709 * Returns the element this view is bound to.
23710 * @return {Roo.Element}
23712 getEl : function(){
23717 * Refreshes the view.
23719 refresh : function(){
23721 this.clearSelections();
23722 this.el.update("");
23724 var records = this.store.getRange();
23725 if(records.length < 1){
23726 this.el.update(this.emptyText);
23729 for(var i = 0, len = records.length; i < len; i++){
23730 var data = this.prepareData(records[i].data, i, records[i]);
23731 html[html.length] = t.apply(data);
23733 this.el.update(html.join(""));
23734 this.nodes = this.el.dom.childNodes;
23735 this.updateIndexes(0);
23739 * Function to override to reformat the data that is sent to
23740 * the template for each node.
23741 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23742 * a JSON object for an UpdateManager bound view).
23744 prepareData : function(data){
23748 onUpdate : function(ds, record){
23749 this.clearSelections();
23750 var index = this.store.indexOf(record);
23751 var n = this.nodes[index];
23752 this.tpl.insertBefore(n, this.prepareData(record.data));
23753 n.parentNode.removeChild(n);
23754 this.updateIndexes(index, index);
23757 onAdd : function(ds, records, index){
23758 this.clearSelections();
23759 if(this.nodes.length == 0){
23763 var n = this.nodes[index];
23764 for(var i = 0, len = records.length; i < len; i++){
23765 var d = this.prepareData(records[i].data);
23767 this.tpl.insertBefore(n, d);
23769 this.tpl.append(this.el, d);
23772 this.updateIndexes(index);
23775 onRemove : function(ds, record, index){
23776 this.clearSelections();
23777 this.el.dom.removeChild(this.nodes[index]);
23778 this.updateIndexes(index);
23782 * Refresh an individual node.
23783 * @param {Number} index
23785 refreshNode : function(index){
23786 this.onUpdate(this.store, this.store.getAt(index));
23789 updateIndexes : function(startIndex, endIndex){
23790 var ns = this.nodes;
23791 startIndex = startIndex || 0;
23792 endIndex = endIndex || ns.length - 1;
23793 for(var i = startIndex; i <= endIndex; i++){
23794 ns[i].nodeIndex = i;
23799 * Changes the data store this view uses and refresh the view.
23800 * @param {Store} store
23802 setStore : function(store, initial){
23803 if(!initial && this.store){
23804 this.store.un("datachanged", this.refresh);
23805 this.store.un("add", this.onAdd);
23806 this.store.un("remove", this.onRemove);
23807 this.store.un("update", this.onUpdate);
23808 this.store.un("clear", this.refresh);
23812 store.on("datachanged", this.refresh, this);
23813 store.on("add", this.onAdd, this);
23814 store.on("remove", this.onRemove, this);
23815 store.on("update", this.onUpdate, this);
23816 store.on("clear", this.refresh, this);
23825 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23826 * @param {HTMLElement} node
23827 * @return {HTMLElement} The template node
23829 findItemFromChild : function(node){
23830 var el = this.el.dom;
23831 if(!node || node.parentNode == el){
23834 var p = node.parentNode;
23835 while(p && p != el){
23836 if(p.parentNode == el){
23845 onClick : function(e){
23846 var item = this.findItemFromChild(e.getTarget());
23848 var index = this.indexOf(item);
23849 if(this.onItemClick(item, index, e) !== false){
23850 this.fireEvent("click", this, index, item, e);
23853 this.clearSelections();
23858 onContextMenu : function(e){
23859 var item = this.findItemFromChild(e.getTarget());
23861 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23866 onDblClick : function(e){
23867 var item = this.findItemFromChild(e.getTarget());
23869 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23873 onItemClick : function(item, index, e){
23874 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23877 if(this.multiSelect || this.singleSelect){
23878 if(this.multiSelect && e.shiftKey && this.lastSelection){
23879 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23881 this.select(item, this.multiSelect && e.ctrlKey);
23882 this.lastSelection = item;
23884 e.preventDefault();
23890 * Get the number of selected nodes.
23893 getSelectionCount : function(){
23894 return this.selections.length;
23898 * Get the currently selected nodes.
23899 * @return {Array} An array of HTMLElements
23901 getSelectedNodes : function(){
23902 return this.selections;
23906 * Get the indexes of the selected nodes.
23909 getSelectedIndexes : function(){
23910 var indexes = [], s = this.selections;
23911 for(var i = 0, len = s.length; i < len; i++){
23912 indexes.push(s[i].nodeIndex);
23918 * Clear all selections
23919 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23921 clearSelections : function(suppressEvent){
23922 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23923 this.cmp.elements = this.selections;
23924 this.cmp.removeClass(this.selectedClass);
23925 this.selections = [];
23926 if(!suppressEvent){
23927 this.fireEvent("selectionchange", this, this.selections);
23933 * Returns true if the passed node is selected
23934 * @param {HTMLElement/Number} node The node or node index
23935 * @return {Boolean}
23937 isSelected : function(node){
23938 var s = this.selections;
23942 node = this.getNode(node);
23943 return s.indexOf(node) !== -1;
23948 * @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
23949 * @param {Boolean} keepExisting (optional) true to keep existing selections
23950 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23952 select : function(nodeInfo, keepExisting, suppressEvent){
23953 if(nodeInfo instanceof Array){
23955 this.clearSelections(true);
23957 for(var i = 0, len = nodeInfo.length; i < len; i++){
23958 this.select(nodeInfo[i], true, true);
23961 var node = this.getNode(nodeInfo);
23962 if(node && !this.isSelected(node)){
23964 this.clearSelections(true);
23966 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23967 Roo.fly(node).addClass(this.selectedClass);
23968 this.selections.push(node);
23969 if(!suppressEvent){
23970 this.fireEvent("selectionchange", this, this.selections);
23978 * Gets a template node.
23979 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23980 * @return {HTMLElement} The node or null if it wasn't found
23982 getNode : function(nodeInfo){
23983 if(typeof nodeInfo == "string"){
23984 return document.getElementById(nodeInfo);
23985 }else if(typeof nodeInfo == "number"){
23986 return this.nodes[nodeInfo];
23992 * Gets a range template nodes.
23993 * @param {Number} startIndex
23994 * @param {Number} endIndex
23995 * @return {Array} An array of nodes
23997 getNodes : function(start, end){
23998 var ns = this.nodes;
23999 start = start || 0;
24000 end = typeof end == "undefined" ? ns.length - 1 : end;
24003 for(var i = start; i <= end; i++){
24007 for(var i = start; i >= end; i--){
24015 * Finds the index of the passed node
24016 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24017 * @return {Number} The index of the node or -1
24019 indexOf : function(node){
24020 node = this.getNode(node);
24021 if(typeof node.nodeIndex == "number"){
24022 return node.nodeIndex;
24024 var ns = this.nodes;
24025 for(var i = 0, len = ns.length; i < len; i++){
24035 * Ext JS Library 1.1.1
24036 * Copyright(c) 2006-2007, Ext JS, LLC.
24038 * Originally Released Under LGPL - original licence link has changed is not relivant.
24041 * <script type="text/javascript">
24045 * @class Roo.JsonView
24046 * @extends Roo.View
24047 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24049 var view = new Roo.JsonView({
24050 container: "my-element",
24051 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24056 // listen for node click?
24057 view.on("click", function(vw, index, node, e){
24058 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24061 // direct load of JSON data
24062 view.load("foobar.php");
24064 // Example from my blog list
24065 var tpl = new Roo.Template(
24066 '<div class="entry">' +
24067 '<a class="entry-title" href="{link}">{title}</a>' +
24068 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24069 "</div><hr />"
24072 var moreView = new Roo.JsonView({
24073 container : "entry-list",
24077 moreView.on("beforerender", this.sortEntries, this);
24079 url: "/blog/get-posts.php",
24080 params: "allposts=true",
24081 text: "Loading Blog Entries..."
24085 * Note: old code is supported with arguments : (container, template, config)
24089 * Create a new JsonView
24091 * @param {Object} config The config object
24094 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24097 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24099 var um = this.el.getUpdateManager();
24100 um.setRenderer(this);
24101 um.on("update", this.onLoad, this);
24102 um.on("failure", this.onLoadException, this);
24105 * @event beforerender
24106 * Fires before rendering of the downloaded JSON data.
24107 * @param {Roo.JsonView} this
24108 * @param {Object} data The JSON data loaded
24112 * Fires when data is loaded.
24113 * @param {Roo.JsonView} this
24114 * @param {Object} data The JSON data loaded
24115 * @param {Object} response The raw Connect response object
24118 * @event loadexception
24119 * Fires when loading fails.
24120 * @param {Roo.JsonView} this
24121 * @param {Object} response The raw Connect response object
24124 'beforerender' : true,
24126 'loadexception' : true
24129 Roo.extend(Roo.JsonView, Roo.View, {
24131 * @type {String} The root property in the loaded JSON object that contains the data
24136 * Refreshes the view.
24138 refresh : function(){
24139 this.clearSelections();
24140 this.el.update("");
24142 var o = this.jsonData;
24143 if(o && o.length > 0){
24144 for(var i = 0, len = o.length; i < len; i++){
24145 var data = this.prepareData(o[i], i, o);
24146 html[html.length] = this.tpl.apply(data);
24149 html.push(this.emptyText);
24151 this.el.update(html.join(""));
24152 this.nodes = this.el.dom.childNodes;
24153 this.updateIndexes(0);
24157 * 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.
24158 * @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:
24161 url: "your-url.php",
24162 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24163 callback: yourFunction,
24164 scope: yourObject, //(optional scope)
24167 text: "Loading...",
24172 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24173 * 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.
24174 * @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}
24175 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24176 * @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.
24179 var um = this.el.getUpdateManager();
24180 um.update.apply(um, arguments);
24183 render : function(el, response){
24184 this.clearSelections();
24185 this.el.update("");
24188 o = Roo.util.JSON.decode(response.responseText);
24191 o = o[this.jsonRoot];
24196 * The current JSON data or null
24199 this.beforeRender();
24204 * Get the number of records in the current JSON dataset
24207 getCount : function(){
24208 return this.jsonData ? this.jsonData.length : 0;
24212 * Returns the JSON object for the specified node(s)
24213 * @param {HTMLElement/Array} node The node or an array of nodes
24214 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24215 * you get the JSON object for the node
24217 getNodeData : function(node){
24218 if(node instanceof Array){
24220 for(var i = 0, len = node.length; i < len; i++){
24221 data.push(this.getNodeData(node[i]));
24225 return this.jsonData[this.indexOf(node)] || null;
24228 beforeRender : function(){
24229 this.snapshot = this.jsonData;
24231 this.sort.apply(this, this.sortInfo);
24233 this.fireEvent("beforerender", this, this.jsonData);
24236 onLoad : function(el, o){
24237 this.fireEvent("load", this, this.jsonData, o);
24240 onLoadException : function(el, o){
24241 this.fireEvent("loadexception", this, o);
24245 * Filter the data by a specific property.
24246 * @param {String} property A property on your JSON objects
24247 * @param {String/RegExp} value Either string that the property values
24248 * should start with, or a RegExp to test against the property
24250 filter : function(property, value){
24253 var ss = this.snapshot;
24254 if(typeof value == "string"){
24255 var vlen = value.length;
24257 this.clearFilter();
24260 value = value.toLowerCase();
24261 for(var i = 0, len = ss.length; i < len; i++){
24263 if(o[property].substr(0, vlen).toLowerCase() == value){
24267 } else if(value.exec){ // regex?
24268 for(var i = 0, len = ss.length; i < len; i++){
24270 if(value.test(o[property])){
24277 this.jsonData = data;
24283 * Filter by a function. The passed function will be called with each
24284 * object in the current dataset. If the function returns true the value is kept,
24285 * otherwise it is filtered.
24286 * @param {Function} fn
24287 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24289 filterBy : function(fn, scope){
24292 var ss = this.snapshot;
24293 for(var i = 0, len = ss.length; i < len; i++){
24295 if(fn.call(scope || this, o)){
24299 this.jsonData = data;
24305 * Clears the current filter.
24307 clearFilter : function(){
24308 if(this.snapshot && this.jsonData != this.snapshot){
24309 this.jsonData = this.snapshot;
24316 * Sorts the data for this view and refreshes it.
24317 * @param {String} property A property on your JSON objects to sort on
24318 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24319 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24321 sort : function(property, dir, sortType){
24322 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24325 var dsc = dir && dir.toLowerCase() == "desc";
24326 var f = function(o1, o2){
24327 var v1 = sortType ? sortType(o1[p]) : o1[p];
24328 var v2 = sortType ? sortType(o2[p]) : o2[p];
24331 return dsc ? +1 : -1;
24332 } else if(v1 > v2){
24333 return dsc ? -1 : +1;
24338 this.jsonData.sort(f);
24340 if(this.jsonData != this.snapshot){
24341 this.snapshot.sort(f);
24347 * Ext JS Library 1.1.1
24348 * Copyright(c) 2006-2007, Ext JS, LLC.
24350 * Originally Released Under LGPL - original licence link has changed is not relivant.
24353 * <script type="text/javascript">
24358 * @class Roo.ColorPalette
24359 * @extends Roo.Component
24360 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24361 * Here's an example of typical usage:
24363 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24364 cp.render('my-div');
24366 cp.on('select', function(palette, selColor){
24367 // do something with selColor
24371 * Create a new ColorPalette
24372 * @param {Object} config The config object
24374 Roo.ColorPalette = function(config){
24375 Roo.ColorPalette.superclass.constructor.call(this, config);
24379 * Fires when a color is selected
24380 * @param {ColorPalette} this
24381 * @param {String} color The 6-digit color hex code (without the # symbol)
24387 this.on("select", this.handler, this.scope, true);
24390 Roo.extend(Roo.ColorPalette, Roo.Component, {
24392 * @cfg {String} itemCls
24393 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24395 itemCls : "x-color-palette",
24397 * @cfg {String} value
24398 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24399 * the hex codes are case-sensitive.
24402 clickEvent:'click',
24404 ctype: "Roo.ColorPalette",
24407 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24409 allowReselect : false,
24412 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24413 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24414 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24415 * of colors with the width setting until the box is symmetrical.</p>
24416 * <p>You can override individual colors if needed:</p>
24418 var cp = new Roo.ColorPalette();
24419 cp.colors[0] = "FF0000"; // change the first box to red
24422 Or you can provide a custom array of your own for complete control:
24424 var cp = new Roo.ColorPalette();
24425 cp.colors = ["000000", "993300", "333300"];
24430 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24431 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24432 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24433 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24434 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24438 onRender : function(container, position){
24439 var t = new Roo.MasterTemplate(
24440 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24442 var c = this.colors;
24443 for(var i = 0, len = c.length; i < len; i++){
24446 var el = document.createElement("div");
24447 el.className = this.itemCls;
24449 container.dom.insertBefore(el, position);
24450 this.el = Roo.get(el);
24451 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24452 if(this.clickEvent != 'click'){
24453 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24458 afterRender : function(){
24459 Roo.ColorPalette.superclass.afterRender.call(this);
24461 var s = this.value;
24468 handleClick : function(e, t){
24469 e.preventDefault();
24470 if(!this.disabled){
24471 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24472 this.select(c.toUpperCase());
24477 * Selects the specified color in the palette (fires the select event)
24478 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24480 select : function(color){
24481 color = color.replace("#", "");
24482 if(color != this.value || this.allowReselect){
24485 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24487 el.child("a.color-"+color).addClass("x-color-palette-sel");
24488 this.value = color;
24489 this.fireEvent("select", this, color);
24494 * Ext JS Library 1.1.1
24495 * Copyright(c) 2006-2007, Ext JS, LLC.
24497 * Originally Released Under LGPL - original licence link has changed is not relivant.
24500 * <script type="text/javascript">
24504 * @class Roo.DatePicker
24505 * @extends Roo.Component
24506 * Simple date picker class.
24508 * Create a new DatePicker
24509 * @param {Object} config The config object
24511 Roo.DatePicker = function(config){
24512 Roo.DatePicker.superclass.constructor.call(this, config);
24514 this.value = config && config.value ?
24515 config.value.clearTime() : new Date().clearTime();
24520 * Fires when a date is selected
24521 * @param {DatePicker} this
24522 * @param {Date} date The selected date
24528 this.on("select", this.handler, this.scope || this);
24530 // build the disabledDatesRE
24531 if(!this.disabledDatesRE && this.disabledDates){
24532 var dd = this.disabledDates;
24534 for(var i = 0; i < dd.length; i++){
24536 if(i != dd.length-1) re += "|";
24538 this.disabledDatesRE = new RegExp(re + ")");
24542 Roo.extend(Roo.DatePicker, Roo.Component, {
24544 * @cfg {String} todayText
24545 * The text to display on the button that selects the current date (defaults to "Today")
24547 todayText : "Today",
24549 * @cfg {String} okText
24550 * The text to display on the ok button
24552 okText : " OK ", //   to give the user extra clicking room
24554 * @cfg {String} cancelText
24555 * The text to display on the cancel button
24557 cancelText : "Cancel",
24559 * @cfg {String} todayTip
24560 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24562 todayTip : "{0} (Spacebar)",
24564 * @cfg {Date} minDate
24565 * Minimum allowable date (JavaScript date object, defaults to null)
24569 * @cfg {Date} maxDate
24570 * Maximum allowable date (JavaScript date object, defaults to null)
24574 * @cfg {String} minText
24575 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24577 minText : "This date is before the minimum date",
24579 * @cfg {String} maxText
24580 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24582 maxText : "This date is after the maximum date",
24584 * @cfg {String} format
24585 * The default date format string which can be overriden for localization support. The format must be
24586 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24590 * @cfg {Array} disabledDays
24591 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24593 disabledDays : null,
24595 * @cfg {String} disabledDaysText
24596 * The tooltip to display when the date falls on a disabled day (defaults to "")
24598 disabledDaysText : "",
24600 * @cfg {RegExp} disabledDatesRE
24601 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24603 disabledDatesRE : null,
24605 * @cfg {String} disabledDatesText
24606 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24608 disabledDatesText : "",
24610 * @cfg {Boolean} constrainToViewport
24611 * True to constrain the date picker to the viewport (defaults to true)
24613 constrainToViewport : true,
24615 * @cfg {Array} monthNames
24616 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24618 monthNames : Date.monthNames,
24620 * @cfg {Array} dayNames
24621 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24623 dayNames : Date.dayNames,
24625 * @cfg {String} nextText
24626 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24628 nextText: 'Next Month (Control+Right)',
24630 * @cfg {String} prevText
24631 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24633 prevText: 'Previous Month (Control+Left)',
24635 * @cfg {String} monthYearText
24636 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24638 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24640 * @cfg {Number} startDay
24641 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24645 * @cfg {Bool} showClear
24646 * Show a clear button (usefull for date form elements that can be blank.)
24652 * Sets the value of the date field
24653 * @param {Date} value The date to set
24655 setValue : function(value){
24656 var old = this.value;
24657 this.value = value.clearTime(true);
24659 this.update(this.value);
24664 * Gets the current selected value of the date field
24665 * @return {Date} The selected date
24667 getValue : function(){
24672 focus : function(){
24674 this.update(this.activeDate);
24679 onRender : function(container, position){
24681 '<table cellspacing="0">',
24682 '<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>',
24683 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24684 var dn = this.dayNames;
24685 for(var i = 0; i < 7; i++){
24686 var d = this.startDay+i;
24690 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24692 m[m.length] = "</tr></thead><tbody><tr>";
24693 for(var i = 0; i < 42; i++) {
24694 if(i % 7 == 0 && i != 0){
24695 m[m.length] = "</tr><tr>";
24697 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24699 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24700 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24702 var el = document.createElement("div");
24703 el.className = "x-date-picker";
24704 el.innerHTML = m.join("");
24706 container.dom.insertBefore(el, position);
24708 this.el = Roo.get(el);
24709 this.eventEl = Roo.get(el.firstChild);
24711 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24712 handler: this.showPrevMonth,
24714 preventDefault:true,
24718 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24719 handler: this.showNextMonth,
24721 preventDefault:true,
24725 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24727 this.monthPicker = this.el.down('div.x-date-mp');
24728 this.monthPicker.enableDisplayMode('block');
24730 var kn = new Roo.KeyNav(this.eventEl, {
24731 "left" : function(e){
24733 this.showPrevMonth() :
24734 this.update(this.activeDate.add("d", -1));
24737 "right" : function(e){
24739 this.showNextMonth() :
24740 this.update(this.activeDate.add("d", 1));
24743 "up" : function(e){
24745 this.showNextYear() :
24746 this.update(this.activeDate.add("d", -7));
24749 "down" : function(e){
24751 this.showPrevYear() :
24752 this.update(this.activeDate.add("d", 7));
24755 "pageUp" : function(e){
24756 this.showNextMonth();
24759 "pageDown" : function(e){
24760 this.showPrevMonth();
24763 "enter" : function(e){
24764 e.stopPropagation();
24771 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24773 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24775 this.el.unselectable();
24777 this.cells = this.el.select("table.x-date-inner tbody td");
24778 this.textNodes = this.el.query("table.x-date-inner tbody span");
24780 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24782 tooltip: this.monthYearText
24785 this.mbtn.on('click', this.showMonthPicker, this);
24786 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24789 var today = (new Date()).dateFormat(this.format);
24791 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24792 if (this.showClear) {
24793 baseTb.add( new Roo.Toolbar.Fill());
24796 text: String.format(this.todayText, today),
24797 tooltip: String.format(this.todayTip, today),
24798 handler: this.selectToday,
24802 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24805 if (this.showClear) {
24807 baseTb.add( new Roo.Toolbar.Fill());
24810 cls: 'x-btn-icon x-btn-clear',
24811 handler: function() {
24813 this.fireEvent("select", this, '');
24823 this.update(this.value);
24826 createMonthPicker : function(){
24827 if(!this.monthPicker.dom.firstChild){
24828 var buf = ['<table border="0" cellspacing="0">'];
24829 for(var i = 0; i < 6; i++){
24831 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24832 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24834 '<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>' :
24835 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24839 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24841 '</button><button type="button" class="x-date-mp-cancel">',
24843 '</button></td></tr>',
24846 this.monthPicker.update(buf.join(''));
24847 this.monthPicker.on('click', this.onMonthClick, this);
24848 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24850 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24851 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24853 this.mpMonths.each(function(m, a, i){
24856 m.dom.xmonth = 5 + Math.round(i * .5);
24858 m.dom.xmonth = Math.round((i-1) * .5);
24864 showMonthPicker : function(){
24865 this.createMonthPicker();
24866 var size = this.el.getSize();
24867 this.monthPicker.setSize(size);
24868 this.monthPicker.child('table').setSize(size);
24870 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24871 this.updateMPMonth(this.mpSelMonth);
24872 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24873 this.updateMPYear(this.mpSelYear);
24875 this.monthPicker.slideIn('t', {duration:.2});
24878 updateMPYear : function(y){
24880 var ys = this.mpYears.elements;
24881 for(var i = 1; i <= 10; i++){
24882 var td = ys[i-1], y2;
24884 y2 = y + Math.round(i * .5);
24885 td.firstChild.innerHTML = y2;
24888 y2 = y - (5-Math.round(i * .5));
24889 td.firstChild.innerHTML = y2;
24892 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24896 updateMPMonth : function(sm){
24897 this.mpMonths.each(function(m, a, i){
24898 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24902 selectMPMonth: function(m){
24906 onMonthClick : function(e, t){
24908 var el = new Roo.Element(t), pn;
24909 if(el.is('button.x-date-mp-cancel')){
24910 this.hideMonthPicker();
24912 else if(el.is('button.x-date-mp-ok')){
24913 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24914 this.hideMonthPicker();
24916 else if(pn = el.up('td.x-date-mp-month', 2)){
24917 this.mpMonths.removeClass('x-date-mp-sel');
24918 pn.addClass('x-date-mp-sel');
24919 this.mpSelMonth = pn.dom.xmonth;
24921 else if(pn = el.up('td.x-date-mp-year', 2)){
24922 this.mpYears.removeClass('x-date-mp-sel');
24923 pn.addClass('x-date-mp-sel');
24924 this.mpSelYear = pn.dom.xyear;
24926 else if(el.is('a.x-date-mp-prev')){
24927 this.updateMPYear(this.mpyear-10);
24929 else if(el.is('a.x-date-mp-next')){
24930 this.updateMPYear(this.mpyear+10);
24934 onMonthDblClick : function(e, t){
24936 var el = new Roo.Element(t), pn;
24937 if(pn = el.up('td.x-date-mp-month', 2)){
24938 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24939 this.hideMonthPicker();
24941 else if(pn = el.up('td.x-date-mp-year', 2)){
24942 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24943 this.hideMonthPicker();
24947 hideMonthPicker : function(disableAnim){
24948 if(this.monthPicker){
24949 if(disableAnim === true){
24950 this.monthPicker.hide();
24952 this.monthPicker.slideOut('t', {duration:.2});
24958 showPrevMonth : function(e){
24959 this.update(this.activeDate.add("mo", -1));
24963 showNextMonth : function(e){
24964 this.update(this.activeDate.add("mo", 1));
24968 showPrevYear : function(){
24969 this.update(this.activeDate.add("y", -1));
24973 showNextYear : function(){
24974 this.update(this.activeDate.add("y", 1));
24978 handleMouseWheel : function(e){
24979 var delta = e.getWheelDelta();
24981 this.showPrevMonth();
24983 } else if(delta < 0){
24984 this.showNextMonth();
24990 handleDateClick : function(e, t){
24992 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24993 this.setValue(new Date(t.dateValue));
24994 this.fireEvent("select", this, this.value);
24999 selectToday : function(){
25000 this.setValue(new Date().clearTime());
25001 this.fireEvent("select", this, this.value);
25005 update : function(date){
25006 var vd = this.activeDate;
25007 this.activeDate = date;
25009 var t = date.getTime();
25010 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25011 this.cells.removeClass("x-date-selected");
25012 this.cells.each(function(c){
25013 if(c.dom.firstChild.dateValue == t){
25014 c.addClass("x-date-selected");
25015 setTimeout(function(){
25016 try{c.dom.firstChild.focus();}catch(e){}
25024 var days = date.getDaysInMonth();
25025 var firstOfMonth = date.getFirstDateOfMonth();
25026 var startingPos = firstOfMonth.getDay()-this.startDay;
25028 if(startingPos <= this.startDay){
25032 var pm = date.add("mo", -1);
25033 var prevStart = pm.getDaysInMonth()-startingPos;
25035 var cells = this.cells.elements;
25036 var textEls = this.textNodes;
25037 days += startingPos;
25039 // convert everything to numbers so it's fast
25040 var day = 86400000;
25041 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25042 var today = new Date().clearTime().getTime();
25043 var sel = date.clearTime().getTime();
25044 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25045 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25046 var ddMatch = this.disabledDatesRE;
25047 var ddText = this.disabledDatesText;
25048 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25049 var ddaysText = this.disabledDaysText;
25050 var format = this.format;
25052 var setCellClass = function(cal, cell){
25054 var t = d.getTime();
25055 cell.firstChild.dateValue = t;
25057 cell.className += " x-date-today";
25058 cell.title = cal.todayText;
25061 cell.className += " x-date-selected";
25062 setTimeout(function(){
25063 try{cell.firstChild.focus();}catch(e){}
25068 cell.className = " x-date-disabled";
25069 cell.title = cal.minText;
25073 cell.className = " x-date-disabled";
25074 cell.title = cal.maxText;
25078 if(ddays.indexOf(d.getDay()) != -1){
25079 cell.title = ddaysText;
25080 cell.className = " x-date-disabled";
25083 if(ddMatch && format){
25084 var fvalue = d.dateFormat(format);
25085 if(ddMatch.test(fvalue)){
25086 cell.title = ddText.replace("%0", fvalue);
25087 cell.className = " x-date-disabled";
25093 for(; i < startingPos; i++) {
25094 textEls[i].innerHTML = (++prevStart);
25095 d.setDate(d.getDate()+1);
25096 cells[i].className = "x-date-prevday";
25097 setCellClass(this, cells[i]);
25099 for(; i < days; i++){
25100 intDay = i - startingPos + 1;
25101 textEls[i].innerHTML = (intDay);
25102 d.setDate(d.getDate()+1);
25103 cells[i].className = "x-date-active";
25104 setCellClass(this, cells[i]);
25107 for(; i < 42; i++) {
25108 textEls[i].innerHTML = (++extraDays);
25109 d.setDate(d.getDate()+1);
25110 cells[i].className = "x-date-nextday";
25111 setCellClass(this, cells[i]);
25114 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25116 if(!this.internalRender){
25117 var main = this.el.dom.firstChild;
25118 var w = main.offsetWidth;
25119 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25120 Roo.fly(main).setWidth(w);
25121 this.internalRender = true;
25122 // opera does not respect the auto grow header center column
25123 // then, after it gets a width opera refuses to recalculate
25124 // without a second pass
25125 if(Roo.isOpera && !this.secondPass){
25126 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25127 this.secondPass = true;
25128 this.update.defer(10, this, [date]);
25134 * Ext JS Library 1.1.1
25135 * Copyright(c) 2006-2007, Ext JS, LLC.
25137 * Originally Released Under LGPL - original licence link has changed is not relivant.
25140 * <script type="text/javascript">
25143 * @class Roo.TabPanel
25144 * @extends Roo.util.Observable
25145 * A lightweight tab container.
25149 // basic tabs 1, built from existing content
25150 var tabs = new Roo.TabPanel("tabs1");
25151 tabs.addTab("script", "View Script");
25152 tabs.addTab("markup", "View Markup");
25153 tabs.activate("script");
25155 // more advanced tabs, built from javascript
25156 var jtabs = new Roo.TabPanel("jtabs");
25157 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25159 // set up the UpdateManager
25160 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25161 var updater = tab2.getUpdateManager();
25162 updater.setDefaultUrl("ajax1.htm");
25163 tab2.on('activate', updater.refresh, updater, true);
25165 // Use setUrl for Ajax loading
25166 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25167 tab3.setUrl("ajax2.htm", null, true);
25170 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25173 jtabs.activate("jtabs-1");
25176 * Create a new TabPanel.
25177 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25178 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25180 Roo.TabPanel = function(container, config){
25182 * The container element for this TabPanel.
25183 * @type Roo.Element
25185 this.el = Roo.get(container, true);
25187 if(typeof config == "boolean"){
25188 this.tabPosition = config ? "bottom" : "top";
25190 Roo.apply(this, config);
25193 if(this.tabPosition == "bottom"){
25194 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25195 this.el.addClass("x-tabs-bottom");
25197 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25198 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25199 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25201 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25203 if(this.tabPosition != "bottom"){
25204 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25205 * @type Roo.Element
25207 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25208 this.el.addClass("x-tabs-top");
25212 this.bodyEl.setStyle("position", "relative");
25214 this.active = null;
25215 this.activateDelegate = this.activate.createDelegate(this);
25220 * Fires when the active tab changes
25221 * @param {Roo.TabPanel} this
25222 * @param {Roo.TabPanelItem} activePanel The new active tab
25226 * @event beforetabchange
25227 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25228 * @param {Roo.TabPanel} this
25229 * @param {Object} e Set cancel to true on this object to cancel the tab change
25230 * @param {Roo.TabPanelItem} tab The tab being changed to
25232 "beforetabchange" : true
25235 Roo.EventManager.onWindowResize(this.onResize, this);
25236 this.cpad = this.el.getPadding("lr");
25237 this.hiddenCount = 0;
25239 Roo.TabPanel.superclass.constructor.call(this);
25242 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25244 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25246 tabPosition : "top",
25248 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25250 currentTabWidth : 0,
25252 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25256 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25260 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25262 preferredTabWidth : 175,
25264 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25266 resizeTabs : false,
25268 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25270 monitorResize : true,
25273 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25274 * @param {String} id The id of the div to use <b>or create</b>
25275 * @param {String} text The text for the tab
25276 * @param {String} content (optional) Content to put in the TabPanelItem body
25277 * @param {Boolean} closable (optional) True to create a close icon on the tab
25278 * @return {Roo.TabPanelItem} The created TabPanelItem
25280 addTab : function(id, text, content, closable){
25281 var item = new Roo.TabPanelItem(this, id, text, closable);
25282 this.addTabItem(item);
25284 item.setContent(content);
25290 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25291 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25292 * @return {Roo.TabPanelItem}
25294 getTab : function(id){
25295 return this.items[id];
25299 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25300 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25302 hideTab : function(id){
25303 var t = this.items[id];
25306 this.hiddenCount++;
25307 this.autoSizeTabs();
25312 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25313 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25315 unhideTab : function(id){
25316 var t = this.items[id];
25318 t.setHidden(false);
25319 this.hiddenCount--;
25320 this.autoSizeTabs();
25325 * Adds an existing {@link Roo.TabPanelItem}.
25326 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25328 addTabItem : function(item){
25329 this.items[item.id] = item;
25330 this.items.push(item);
25331 if(this.resizeTabs){
25332 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25333 this.autoSizeTabs();
25340 * Removes a {@link Roo.TabPanelItem}.
25341 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25343 removeTab : function(id){
25344 var items = this.items;
25345 var tab = items[id];
25346 if(!tab) { return; }
25347 var index = items.indexOf(tab);
25348 if(this.active == tab && items.length > 1){
25349 var newTab = this.getNextAvailable(index);
25354 this.stripEl.dom.removeChild(tab.pnode.dom);
25355 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25356 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25358 items.splice(index, 1);
25359 delete this.items[tab.id];
25360 tab.fireEvent("close", tab);
25361 tab.purgeListeners();
25362 this.autoSizeTabs();
25365 getNextAvailable : function(start){
25366 var items = this.items;
25368 // look for a next tab that will slide over to
25369 // replace the one being removed
25370 while(index < items.length){
25371 var item = items[++index];
25372 if(item && !item.isHidden()){
25376 // if one isn't found select the previous tab (on the left)
25379 var item = items[--index];
25380 if(item && !item.isHidden()){
25388 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25389 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25391 disableTab : function(id){
25392 var tab = this.items[id];
25393 if(tab && this.active != tab){
25399 * Enables a {@link Roo.TabPanelItem} that is disabled.
25400 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25402 enableTab : function(id){
25403 var tab = this.items[id];
25408 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25409 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25410 * @return {Roo.TabPanelItem} The TabPanelItem.
25412 activate : function(id){
25413 var tab = this.items[id];
25417 if(tab == this.active || tab.disabled){
25421 this.fireEvent("beforetabchange", this, e, tab);
25422 if(e.cancel !== true && !tab.disabled){
25424 this.active.hide();
25426 this.active = this.items[id];
25427 this.active.show();
25428 this.fireEvent("tabchange", this, this.active);
25434 * Gets the active {@link Roo.TabPanelItem}.
25435 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25437 getActiveTab : function(){
25438 return this.active;
25442 * Updates the tab body element to fit the height of the container element
25443 * for overflow scrolling
25444 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25446 syncHeight : function(targetHeight){
25447 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25448 var bm = this.bodyEl.getMargins();
25449 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25450 this.bodyEl.setHeight(newHeight);
25454 onResize : function(){
25455 if(this.monitorResize){
25456 this.autoSizeTabs();
25461 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25463 beginUpdate : function(){
25464 this.updating = true;
25468 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25470 endUpdate : function(){
25471 this.updating = false;
25472 this.autoSizeTabs();
25476 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25478 autoSizeTabs : function(){
25479 var count = this.items.length;
25480 var vcount = count - this.hiddenCount;
25481 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25482 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25483 var availWidth = Math.floor(w / vcount);
25484 var b = this.stripBody;
25485 if(b.getWidth() > w){
25486 var tabs = this.items;
25487 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25488 if(availWidth < this.minTabWidth){
25489 /*if(!this.sleft){ // incomplete scrolling code
25490 this.createScrollButtons();
25493 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25496 if(this.currentTabWidth < this.preferredTabWidth){
25497 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25503 * Returns the number of tabs in this TabPanel.
25506 getCount : function(){
25507 return this.items.length;
25511 * Resizes all the tabs to the passed width
25512 * @param {Number} The new width
25514 setTabWidth : function(width){
25515 this.currentTabWidth = width;
25516 for(var i = 0, len = this.items.length; i < len; i++) {
25517 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25522 * Destroys this TabPanel
25523 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25525 destroy : function(removeEl){
25526 Roo.EventManager.removeResizeListener(this.onResize, this);
25527 for(var i = 0, len = this.items.length; i < len; i++){
25528 this.items[i].purgeListeners();
25530 if(removeEl === true){
25531 this.el.update("");
25538 * @class Roo.TabPanelItem
25539 * @extends Roo.util.Observable
25540 * Represents an individual item (tab plus body) in a TabPanel.
25541 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25542 * @param {String} id The id of this TabPanelItem
25543 * @param {String} text The text for the tab of this TabPanelItem
25544 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25546 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25548 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25549 * @type Roo.TabPanel
25551 this.tabPanel = tabPanel;
25553 * The id for this TabPanelItem
25558 this.disabled = false;
25562 this.loaded = false;
25563 this.closable = closable;
25566 * The body element for this TabPanelItem.
25567 * @type Roo.Element
25569 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25570 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25571 this.bodyEl.setStyle("display", "block");
25572 this.bodyEl.setStyle("zoom", "1");
25575 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25577 this.el = Roo.get(els.el, true);
25578 this.inner = Roo.get(els.inner, true);
25579 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25580 this.pnode = Roo.get(els.el.parentNode, true);
25581 this.el.on("mousedown", this.onTabMouseDown, this);
25582 this.el.on("click", this.onTabClick, this);
25585 var c = Roo.get(els.close, true);
25586 c.dom.title = this.closeText;
25587 c.addClassOnOver("close-over");
25588 c.on("click", this.closeClick, this);
25594 * Fires when this tab becomes the active tab.
25595 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25596 * @param {Roo.TabPanelItem} this
25600 * @event beforeclose
25601 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25602 * @param {Roo.TabPanelItem} this
25603 * @param {Object} e Set cancel to true on this object to cancel the close.
25605 "beforeclose": true,
25608 * Fires when this tab is closed.
25609 * @param {Roo.TabPanelItem} this
25613 * @event deactivate
25614 * Fires when this tab is no longer the active tab.
25615 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25616 * @param {Roo.TabPanelItem} this
25618 "deactivate" : true
25620 this.hidden = false;
25622 Roo.TabPanelItem.superclass.constructor.call(this);
25625 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25626 purgeListeners : function(){
25627 Roo.util.Observable.prototype.purgeListeners.call(this);
25628 this.el.removeAllListeners();
25631 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25634 this.pnode.addClass("on");
25637 this.tabPanel.stripWrap.repaint();
25639 this.fireEvent("activate", this.tabPanel, this);
25643 * Returns true if this tab is the active tab.
25644 * @return {Boolean}
25646 isActive : function(){
25647 return this.tabPanel.getActiveTab() == this;
25651 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25654 this.pnode.removeClass("on");
25656 this.fireEvent("deactivate", this.tabPanel, this);
25659 hideAction : function(){
25660 this.bodyEl.hide();
25661 this.bodyEl.setStyle("position", "absolute");
25662 this.bodyEl.setLeft("-20000px");
25663 this.bodyEl.setTop("-20000px");
25666 showAction : function(){
25667 this.bodyEl.setStyle("position", "relative");
25668 this.bodyEl.setTop("");
25669 this.bodyEl.setLeft("");
25670 this.bodyEl.show();
25674 * Set the tooltip for the tab.
25675 * @param {String} tooltip The tab's tooltip
25677 setTooltip : function(text){
25678 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25679 this.textEl.dom.qtip = text;
25680 this.textEl.dom.removeAttribute('title');
25682 this.textEl.dom.title = text;
25686 onTabClick : function(e){
25687 e.preventDefault();
25688 this.tabPanel.activate(this.id);
25691 onTabMouseDown : function(e){
25692 e.preventDefault();
25693 this.tabPanel.activate(this.id);
25696 getWidth : function(){
25697 return this.inner.getWidth();
25700 setWidth : function(width){
25701 var iwidth = width - this.pnode.getPadding("lr");
25702 this.inner.setWidth(iwidth);
25703 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25704 this.pnode.setWidth(width);
25708 * Show or hide the tab
25709 * @param {Boolean} hidden True to hide or false to show.
25711 setHidden : function(hidden){
25712 this.hidden = hidden;
25713 this.pnode.setStyle("display", hidden ? "none" : "");
25717 * Returns true if this tab is "hidden"
25718 * @return {Boolean}
25720 isHidden : function(){
25721 return this.hidden;
25725 * Returns the text for this tab
25728 getText : function(){
25732 autoSize : function(){
25733 //this.el.beginMeasure();
25734 this.textEl.setWidth(1);
25735 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25736 //this.el.endMeasure();
25740 * Sets the text for the tab (Note: this also sets the tooltip text)
25741 * @param {String} text The tab's text and tooltip
25743 setText : function(text){
25745 this.textEl.update(text);
25746 this.setTooltip(text);
25747 if(!this.tabPanel.resizeTabs){
25752 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25754 activate : function(){
25755 this.tabPanel.activate(this.id);
25759 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25761 disable : function(){
25762 if(this.tabPanel.active != this){
25763 this.disabled = true;
25764 this.pnode.addClass("disabled");
25769 * Enables this TabPanelItem if it was previously disabled.
25771 enable : function(){
25772 this.disabled = false;
25773 this.pnode.removeClass("disabled");
25777 * Sets the content for this TabPanelItem.
25778 * @param {String} content The content
25779 * @param {Boolean} loadScripts true to look for and load scripts
25781 setContent : function(content, loadScripts){
25782 this.bodyEl.update(content, loadScripts);
25786 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25787 * @return {Roo.UpdateManager} The UpdateManager
25789 getUpdateManager : function(){
25790 return this.bodyEl.getUpdateManager();
25794 * Set a URL to be used to load the content for this TabPanelItem.
25795 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25796 * @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)
25797 * @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)
25798 * @return {Roo.UpdateManager} The UpdateManager
25800 setUrl : function(url, params, loadOnce){
25801 if(this.refreshDelegate){
25802 this.un('activate', this.refreshDelegate);
25804 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25805 this.on("activate", this.refreshDelegate);
25806 return this.bodyEl.getUpdateManager();
25810 _handleRefresh : function(url, params, loadOnce){
25811 if(!loadOnce || !this.loaded){
25812 var updater = this.bodyEl.getUpdateManager();
25813 updater.update(url, params, this._setLoaded.createDelegate(this));
25818 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25819 * Will fail silently if the setUrl method has not been called.
25820 * This does not activate the panel, just updates its content.
25822 refresh : function(){
25823 if(this.refreshDelegate){
25824 this.loaded = false;
25825 this.refreshDelegate();
25830 _setLoaded : function(){
25831 this.loaded = true;
25835 closeClick : function(e){
25838 this.fireEvent("beforeclose", this, o);
25839 if(o.cancel !== true){
25840 this.tabPanel.removeTab(this.id);
25844 * The text displayed in the tooltip for the close icon.
25847 closeText : "Close this tab"
25851 Roo.TabPanel.prototype.createStrip = function(container){
25852 var strip = document.createElement("div");
25853 strip.className = "x-tabs-wrap";
25854 container.appendChild(strip);
25858 Roo.TabPanel.prototype.createStripList = function(strip){
25859 // div wrapper for retard IE
25860 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
25861 return strip.firstChild.firstChild.firstChild.firstChild;
25864 Roo.TabPanel.prototype.createBody = function(container){
25865 var body = document.createElement("div");
25866 Roo.id(body, "tab-body");
25867 Roo.fly(body).addClass("x-tabs-body");
25868 container.appendChild(body);
25872 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25873 var body = Roo.getDom(id);
25875 body = document.createElement("div");
25878 Roo.fly(body).addClass("x-tabs-item-body");
25879 bodyEl.insertBefore(body, bodyEl.firstChild);
25883 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25884 var td = document.createElement("td");
25885 stripEl.appendChild(td);
25887 td.className = "x-tabs-closable";
25888 if(!this.closeTpl){
25889 this.closeTpl = new Roo.Template(
25890 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25891 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25892 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25895 var el = this.closeTpl.overwrite(td, {"text": text});
25896 var close = el.getElementsByTagName("div")[0];
25897 var inner = el.getElementsByTagName("em")[0];
25898 return {"el": el, "close": close, "inner": inner};
25901 this.tabTpl = new Roo.Template(
25902 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25903 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25906 var el = this.tabTpl.overwrite(td, {"text": text});
25907 var inner = el.getElementsByTagName("em")[0];
25908 return {"el": el, "inner": inner};
25912 * Ext JS Library 1.1.1
25913 * Copyright(c) 2006-2007, Ext JS, LLC.
25915 * Originally Released Under LGPL - original licence link has changed is not relivant.
25918 * <script type="text/javascript">
25922 * @class Roo.Button
25923 * @extends Roo.util.Observable
25924 * Simple Button class
25925 * @cfg {String} text The button text
25926 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25927 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25928 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25929 * @cfg {Object} scope The scope of the handler
25930 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25931 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25932 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25933 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25934 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25935 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25936 applies if enableToggle = true)
25937 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25938 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25939 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25941 * Create a new button
25942 * @param {Object} config The config object
25944 Roo.Button = function(renderTo, config)
25948 renderTo = config.renderTo || false;
25951 Roo.apply(this, config);
25955 * Fires when this button is clicked
25956 * @param {Button} this
25957 * @param {EventObject} e The click event
25962 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25963 * @param {Button} this
25964 * @param {Boolean} pressed
25969 * Fires when the mouse hovers over the button
25970 * @param {Button} this
25971 * @param {Event} e The event object
25973 'mouseover' : true,
25976 * Fires when the mouse exits the button
25977 * @param {Button} this
25978 * @param {Event} e The event object
25983 * Fires when the button is rendered
25984 * @param {Button} this
25989 this.menu = Roo.menu.MenuMgr.get(this.menu);
25991 // register listeners first!! - so render can be captured..
25992 Roo.util.Observable.call(this);
25994 this.render(renderTo);
26000 Roo.extend(Roo.Button, Roo.util.Observable, {
26006 * Read-only. True if this button is hidden
26011 * Read-only. True if this button is disabled
26016 * Read-only. True if this button is pressed (only if enableToggle = true)
26022 * @cfg {Number} tabIndex
26023 * The DOM tabIndex for this button (defaults to undefined)
26025 tabIndex : undefined,
26028 * @cfg {Boolean} enableToggle
26029 * True to enable pressed/not pressed toggling (defaults to false)
26031 enableToggle: false,
26033 * @cfg {Mixed} menu
26034 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26038 * @cfg {String} menuAlign
26039 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26041 menuAlign : "tl-bl?",
26044 * @cfg {String} iconCls
26045 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26047 iconCls : undefined,
26049 * @cfg {String} type
26050 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26055 menuClassTarget: 'tr',
26058 * @cfg {String} clickEvent
26059 * The type of event to map to the button's event handler (defaults to 'click')
26061 clickEvent : 'click',
26064 * @cfg {Boolean} handleMouseEvents
26065 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26067 handleMouseEvents : true,
26070 * @cfg {String} tooltipType
26071 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26073 tooltipType : 'qtip',
26076 * @cfg {String} cls
26077 * A CSS class to apply to the button's main element.
26081 * @cfg {Roo.Template} template (Optional)
26082 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26083 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26084 * require code modifications if required elements (e.g. a button) aren't present.
26088 render : function(renderTo){
26090 if(this.hideParent){
26091 this.parentEl = Roo.get(renderTo);
26093 if(!this.dhconfig){
26094 if(!this.template){
26095 if(!Roo.Button.buttonTemplate){
26096 // hideous table template
26097 Roo.Button.buttonTemplate = new Roo.Template(
26098 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26099 '<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>',
26100 "</tr></tbody></table>");
26102 this.template = Roo.Button.buttonTemplate;
26104 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26105 var btnEl = btn.child("button:first");
26106 btnEl.on('focus', this.onFocus, this);
26107 btnEl.on('blur', this.onBlur, this);
26109 btn.addClass(this.cls);
26112 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26115 btnEl.addClass(this.iconCls);
26117 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26120 if(this.tabIndex !== undefined){
26121 btnEl.dom.tabIndex = this.tabIndex;
26124 if(typeof this.tooltip == 'object'){
26125 Roo.QuickTips.tips(Roo.apply({
26129 btnEl.dom[this.tooltipType] = this.tooltip;
26133 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26137 this.el.dom.id = this.el.id = this.id;
26140 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26141 this.menu.on("show", this.onMenuShow, this);
26142 this.menu.on("hide", this.onMenuHide, this);
26144 btn.addClass("x-btn");
26145 if(Roo.isIE && !Roo.isIE7){
26146 this.autoWidth.defer(1, this);
26150 if(this.handleMouseEvents){
26151 btn.on("mouseover", this.onMouseOver, this);
26152 btn.on("mouseout", this.onMouseOut, this);
26153 btn.on("mousedown", this.onMouseDown, this);
26155 btn.on(this.clickEvent, this.onClick, this);
26156 //btn.on("mouseup", this.onMouseUp, this);
26163 Roo.ButtonToggleMgr.register(this);
26165 this.el.addClass("x-btn-pressed");
26168 var repeater = new Roo.util.ClickRepeater(btn,
26169 typeof this.repeat == "object" ? this.repeat : {}
26171 repeater.on("click", this.onClick, this);
26174 this.fireEvent('render', this);
26178 * Returns the button's underlying element
26179 * @return {Roo.Element} The element
26181 getEl : function(){
26186 * Destroys this Button and removes any listeners.
26188 destroy : function(){
26189 Roo.ButtonToggleMgr.unregister(this);
26190 this.el.removeAllListeners();
26191 this.purgeListeners();
26196 autoWidth : function(){
26198 this.el.setWidth("auto");
26199 if(Roo.isIE7 && Roo.isStrict){
26200 var ib = this.el.child('button');
26201 if(ib && ib.getWidth() > 20){
26203 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26208 this.el.beginMeasure();
26210 if(this.el.getWidth() < this.minWidth){
26211 this.el.setWidth(this.minWidth);
26214 this.el.endMeasure();
26221 * Assigns this button's click handler
26222 * @param {Function} handler The function to call when the button is clicked
26223 * @param {Object} scope (optional) Scope for the function passed in
26225 setHandler : function(handler, scope){
26226 this.handler = handler;
26227 this.scope = scope;
26231 * Sets this button's text
26232 * @param {String} text The button text
26234 setText : function(text){
26237 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26243 * Gets the text for this button
26244 * @return {String} The button text
26246 getText : function(){
26254 this.hidden = false;
26256 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26264 this.hidden = true;
26266 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26271 * Convenience function for boolean show/hide
26272 * @param {Boolean} visible True to show, false to hide
26274 setVisible: function(visible){
26283 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26284 * @param {Boolean} state (optional) Force a particular state
26286 toggle : function(state){
26287 state = state === undefined ? !this.pressed : state;
26288 if(state != this.pressed){
26290 this.el.addClass("x-btn-pressed");
26291 this.pressed = true;
26292 this.fireEvent("toggle", this, true);
26294 this.el.removeClass("x-btn-pressed");
26295 this.pressed = false;
26296 this.fireEvent("toggle", this, false);
26298 if(this.toggleHandler){
26299 this.toggleHandler.call(this.scope || this, this, state);
26307 focus : function(){
26308 this.el.child('button:first').focus();
26312 * Disable this button
26314 disable : function(){
26316 this.el.addClass("x-btn-disabled");
26318 this.disabled = true;
26322 * Enable this button
26324 enable : function(){
26326 this.el.removeClass("x-btn-disabled");
26328 this.disabled = false;
26332 * Convenience function for boolean enable/disable
26333 * @param {Boolean} enabled True to enable, false to disable
26335 setDisabled : function(v){
26336 this[v !== true ? "enable" : "disable"]();
26340 onClick : function(e){
26342 e.preventDefault();
26347 if(!this.disabled){
26348 if(this.enableToggle){
26351 if(this.menu && !this.menu.isVisible()){
26352 this.menu.show(this.el, this.menuAlign);
26354 this.fireEvent("click", this, e);
26356 this.el.removeClass("x-btn-over");
26357 this.handler.call(this.scope || this, this, e);
26362 onMouseOver : function(e){
26363 if(!this.disabled){
26364 this.el.addClass("x-btn-over");
26365 this.fireEvent('mouseover', this, e);
26369 onMouseOut : function(e){
26370 if(!e.within(this.el, true)){
26371 this.el.removeClass("x-btn-over");
26372 this.fireEvent('mouseout', this, e);
26376 onFocus : function(e){
26377 if(!this.disabled){
26378 this.el.addClass("x-btn-focus");
26382 onBlur : function(e){
26383 this.el.removeClass("x-btn-focus");
26386 onMouseDown : function(e){
26387 if(!this.disabled && e.button == 0){
26388 this.el.addClass("x-btn-click");
26389 Roo.get(document).on('mouseup', this.onMouseUp, this);
26393 onMouseUp : function(e){
26395 this.el.removeClass("x-btn-click");
26396 Roo.get(document).un('mouseup', this.onMouseUp, this);
26400 onMenuShow : function(e){
26401 this.el.addClass("x-btn-menu-active");
26404 onMenuHide : function(e){
26405 this.el.removeClass("x-btn-menu-active");
26409 // Private utility class used by Button
26410 Roo.ButtonToggleMgr = function(){
26413 function toggleGroup(btn, state){
26415 var g = groups[btn.toggleGroup];
26416 for(var i = 0, l = g.length; i < l; i++){
26418 g[i].toggle(false);
26425 register : function(btn){
26426 if(!btn.toggleGroup){
26429 var g = groups[btn.toggleGroup];
26431 g = groups[btn.toggleGroup] = [];
26434 btn.on("toggle", toggleGroup);
26437 unregister : function(btn){
26438 if(!btn.toggleGroup){
26441 var g = groups[btn.toggleGroup];
26444 btn.un("toggle", toggleGroup);
26450 * Ext JS Library 1.1.1
26451 * Copyright(c) 2006-2007, Ext JS, LLC.
26453 * Originally Released Under LGPL - original licence link has changed is not relivant.
26456 * <script type="text/javascript">
26460 * @class Roo.SplitButton
26461 * @extends Roo.Button
26462 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26463 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26464 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26465 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26466 * @cfg {String} arrowTooltip The title attribute of the arrow
26468 * Create a new menu button
26469 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26470 * @param {Object} config The config object
26472 Roo.SplitButton = function(renderTo, config){
26473 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26475 * @event arrowclick
26476 * Fires when this button's arrow is clicked
26477 * @param {SplitButton} this
26478 * @param {EventObject} e The click event
26480 this.addEvents({"arrowclick":true});
26483 Roo.extend(Roo.SplitButton, Roo.Button, {
26484 render : function(renderTo){
26485 // this is one sweet looking template!
26486 var tpl = new Roo.Template(
26487 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26488 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26489 '<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>',
26490 "</tbody></table></td><td>",
26491 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26492 '<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>',
26493 "</tbody></table></td></tr></table>"
26495 var btn = tpl.append(renderTo, [this.text, this.type], true);
26496 var btnEl = btn.child("button");
26498 btn.addClass(this.cls);
26501 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26504 btnEl.addClass(this.iconCls);
26506 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26510 if(this.handleMouseEvents){
26511 btn.on("mouseover", this.onMouseOver, this);
26512 btn.on("mouseout", this.onMouseOut, this);
26513 btn.on("mousedown", this.onMouseDown, this);
26514 btn.on("mouseup", this.onMouseUp, this);
26516 btn.on(this.clickEvent, this.onClick, this);
26518 if(typeof this.tooltip == 'object'){
26519 Roo.QuickTips.tips(Roo.apply({
26523 btnEl.dom[this.tooltipType] = this.tooltip;
26526 if(this.arrowTooltip){
26527 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26536 this.el.addClass("x-btn-pressed");
26538 if(Roo.isIE && !Roo.isIE7){
26539 this.autoWidth.defer(1, this);
26544 this.menu.on("show", this.onMenuShow, this);
26545 this.menu.on("hide", this.onMenuHide, this);
26547 this.fireEvent('render', this);
26551 autoWidth : function(){
26553 var tbl = this.el.child("table:first");
26554 var tbl2 = this.el.child("table:last");
26555 this.el.setWidth("auto");
26556 tbl.setWidth("auto");
26557 if(Roo.isIE7 && Roo.isStrict){
26558 var ib = this.el.child('button:first');
26559 if(ib && ib.getWidth() > 20){
26561 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26566 this.el.beginMeasure();
26568 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26569 tbl.setWidth(this.minWidth-tbl2.getWidth());
26572 this.el.endMeasure();
26575 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26579 * Sets this button's click handler
26580 * @param {Function} handler The function to call when the button is clicked
26581 * @param {Object} scope (optional) Scope for the function passed above
26583 setHandler : function(handler, scope){
26584 this.handler = handler;
26585 this.scope = scope;
26589 * Sets this button's arrow click handler
26590 * @param {Function} handler The function to call when the arrow is clicked
26591 * @param {Object} scope (optional) Scope for the function passed above
26593 setArrowHandler : function(handler, scope){
26594 this.arrowHandler = handler;
26595 this.scope = scope;
26601 focus : function(){
26603 this.el.child("button:first").focus();
26608 onClick : function(e){
26609 e.preventDefault();
26610 if(!this.disabled){
26611 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26612 if(this.menu && !this.menu.isVisible()){
26613 this.menu.show(this.el, this.menuAlign);
26615 this.fireEvent("arrowclick", this, e);
26616 if(this.arrowHandler){
26617 this.arrowHandler.call(this.scope || this, this, e);
26620 this.fireEvent("click", this, e);
26622 this.handler.call(this.scope || this, this, e);
26628 onMouseDown : function(e){
26629 if(!this.disabled){
26630 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26634 onMouseUp : function(e){
26635 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26640 // backwards compat
26641 Roo.MenuButton = Roo.SplitButton;/*
26643 * Ext JS Library 1.1.1
26644 * Copyright(c) 2006-2007, Ext JS, LLC.
26646 * Originally Released Under LGPL - original licence link has changed is not relivant.
26649 * <script type="text/javascript">
26653 * @class Roo.Toolbar
26654 * Basic Toolbar class.
26656 * Creates a new Toolbar
26657 * @param {Object} config The config object
26659 Roo.Toolbar = function(container, buttons, config)
26661 /// old consturctor format still supported..
26662 if(container instanceof Array){ // omit the container for later rendering
26663 buttons = container;
26667 if (typeof(container) == 'object' && container.xtype) {
26668 config = container;
26669 container = config.container;
26670 buttons = config.buttons; // not really - use items!!
26673 if (config && config.items) {
26674 xitems = config.items;
26675 delete config.items;
26677 Roo.apply(this, config);
26678 this.buttons = buttons;
26681 this.render(container);
26683 Roo.each(xitems, function(b) {
26689 Roo.Toolbar.prototype = {
26691 * @cfg {Roo.data.Store} items
26692 * array of button configs or elements to add
26696 * @cfg {String/HTMLElement/Element} container
26697 * The id or element that will contain the toolbar
26700 render : function(ct){
26701 this.el = Roo.get(ct);
26703 this.el.addClass(this.cls);
26705 // using a table allows for vertical alignment
26706 // 100% width is needed by Safari...
26707 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26708 this.tr = this.el.child("tr", true);
26710 this.items = new Roo.util.MixedCollection(false, function(o){
26711 return o.id || ("item" + (++autoId));
26714 this.add.apply(this, this.buttons);
26715 delete this.buttons;
26720 * Adds element(s) to the toolbar -- this function takes a variable number of
26721 * arguments of mixed type and adds them to the toolbar.
26722 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26724 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26725 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26726 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26727 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26728 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26729 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26730 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26731 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26732 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26734 * @param {Mixed} arg2
26735 * @param {Mixed} etc.
26738 var a = arguments, l = a.length;
26739 for(var i = 0; i < l; i++){
26744 _add : function(el) {
26747 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26750 if (el.applyTo){ // some kind of form field
26751 return this.addField(el);
26753 if (el.render){ // some kind of Toolbar.Item
26754 return this.addItem(el);
26756 if (typeof el == "string"){ // string
26757 if(el == "separator" || el == "-"){
26758 return this.addSeparator();
26761 return this.addSpacer();
26764 return this.addFill();
26766 return this.addText(el);
26769 if(el.tagName){ // element
26770 return this.addElement(el);
26772 if(typeof el == "object"){ // must be button config?
26773 return this.addButton(el);
26775 // and now what?!?!
26781 * Add an Xtype element
26782 * @param {Object} xtype Xtype Object
26783 * @return {Object} created Object
26785 addxtype : function(e){
26786 return this.add(e);
26790 * Returns the Element for this toolbar.
26791 * @return {Roo.Element}
26793 getEl : function(){
26799 * @return {Roo.Toolbar.Item} The separator item
26801 addSeparator : function(){
26802 return this.addItem(new Roo.Toolbar.Separator());
26806 * Adds a spacer element
26807 * @return {Roo.Toolbar.Spacer} The spacer item
26809 addSpacer : function(){
26810 return this.addItem(new Roo.Toolbar.Spacer());
26814 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26815 * @return {Roo.Toolbar.Fill} The fill item
26817 addFill : function(){
26818 return this.addItem(new Roo.Toolbar.Fill());
26822 * Adds any standard HTML element to the toolbar
26823 * @param {String/HTMLElement/Element} el The element or id of the element to add
26824 * @return {Roo.Toolbar.Item} The element's item
26826 addElement : function(el){
26827 return this.addItem(new Roo.Toolbar.Item(el));
26830 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26831 * @type Roo.util.MixedCollection
26836 * Adds any Toolbar.Item or subclass
26837 * @param {Roo.Toolbar.Item} item
26838 * @return {Roo.Toolbar.Item} The item
26840 addItem : function(item){
26841 var td = this.nextBlock();
26843 this.items.add(item);
26848 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26849 * @param {Object/Array} config A button config or array of configs
26850 * @return {Roo.Toolbar.Button/Array}
26852 addButton : function(config){
26853 if(config instanceof Array){
26855 for(var i = 0, len = config.length; i < len; i++) {
26856 buttons.push(this.addButton(config[i]));
26861 if(!(config instanceof Roo.Toolbar.Button)){
26863 new Roo.Toolbar.SplitButton(config) :
26864 new Roo.Toolbar.Button(config);
26866 var td = this.nextBlock();
26873 * Adds text to the toolbar
26874 * @param {String} text The text to add
26875 * @return {Roo.Toolbar.Item} The element's item
26877 addText : function(text){
26878 return this.addItem(new Roo.Toolbar.TextItem(text));
26882 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26883 * @param {Number} index The index where the item is to be inserted
26884 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26885 * @return {Roo.Toolbar.Button/Item}
26887 insertButton : function(index, item){
26888 if(item instanceof Array){
26890 for(var i = 0, len = item.length; i < len; i++) {
26891 buttons.push(this.insertButton(index + i, item[i]));
26895 if (!(item instanceof Roo.Toolbar.Button)){
26896 item = new Roo.Toolbar.Button(item);
26898 var td = document.createElement("td");
26899 this.tr.insertBefore(td, this.tr.childNodes[index]);
26901 this.items.insert(index, item);
26906 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26907 * @param {Object} config
26908 * @return {Roo.Toolbar.Item} The element's item
26910 addDom : function(config, returnEl){
26911 var td = this.nextBlock();
26912 Roo.DomHelper.overwrite(td, config);
26913 var ti = new Roo.Toolbar.Item(td.firstChild);
26915 this.items.add(ti);
26920 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26921 * @type Roo.util.MixedCollection
26926 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26927 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26928 * @param {Roo.form.Field} field
26929 * @return {Roo.ToolbarItem}
26933 addField : function(field) {
26934 if (!this.fields) {
26936 this.fields = new Roo.util.MixedCollection(false, function(o){
26937 return o.id || ("item" + (++autoId));
26942 var td = this.nextBlock();
26944 var ti = new Roo.Toolbar.Item(td.firstChild);
26946 this.items.add(ti);
26947 this.fields.add(field);
26958 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26959 this.el.child('div').hide();
26967 this.el.child('div').show();
26971 nextBlock : function(){
26972 var td = document.createElement("td");
26973 this.tr.appendChild(td);
26978 destroy : function(){
26979 if(this.items){ // rendered?
26980 Roo.destroy.apply(Roo, this.items.items);
26982 if(this.fields){ // rendered?
26983 Roo.destroy.apply(Roo, this.fields.items);
26985 Roo.Element.uncache(this.el, this.tr);
26990 * @class Roo.Toolbar.Item
26991 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26993 * Creates a new Item
26994 * @param {HTMLElement} el
26996 Roo.Toolbar.Item = function(el){
26997 this.el = Roo.getDom(el);
26998 this.id = Roo.id(this.el);
26999 this.hidden = false;
27002 Roo.Toolbar.Item.prototype = {
27005 * Get this item's HTML Element
27006 * @return {HTMLElement}
27008 getEl : function(){
27013 render : function(td){
27015 td.appendChild(this.el);
27019 * Removes and destroys this item.
27021 destroy : function(){
27022 this.td.parentNode.removeChild(this.td);
27029 this.hidden = false;
27030 this.td.style.display = "";
27037 this.hidden = true;
27038 this.td.style.display = "none";
27042 * Convenience function for boolean show/hide.
27043 * @param {Boolean} visible true to show/false to hide
27045 setVisible: function(visible){
27054 * Try to focus this item.
27056 focus : function(){
27057 Roo.fly(this.el).focus();
27061 * Disables this item.
27063 disable : function(){
27064 Roo.fly(this.td).addClass("x-item-disabled");
27065 this.disabled = true;
27066 this.el.disabled = true;
27070 * Enables this item.
27072 enable : function(){
27073 Roo.fly(this.td).removeClass("x-item-disabled");
27074 this.disabled = false;
27075 this.el.disabled = false;
27081 * @class Roo.Toolbar.Separator
27082 * @extends Roo.Toolbar.Item
27083 * A simple toolbar separator class
27085 * Creates a new Separator
27087 Roo.Toolbar.Separator = function(){
27088 var s = document.createElement("span");
27089 s.className = "ytb-sep";
27090 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27092 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27093 enable:Roo.emptyFn,
27094 disable:Roo.emptyFn,
27099 * @class Roo.Toolbar.Spacer
27100 * @extends Roo.Toolbar.Item
27101 * A simple element that adds extra horizontal space to a toolbar.
27103 * Creates a new Spacer
27105 Roo.Toolbar.Spacer = function(){
27106 var s = document.createElement("div");
27107 s.className = "ytb-spacer";
27108 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27110 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27111 enable:Roo.emptyFn,
27112 disable:Roo.emptyFn,
27117 * @class Roo.Toolbar.Fill
27118 * @extends Roo.Toolbar.Spacer
27119 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27121 * Creates a new Spacer
27123 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27125 render : function(td){
27126 td.style.width = '100%';
27127 Roo.Toolbar.Fill.superclass.render.call(this, td);
27132 * @class Roo.Toolbar.TextItem
27133 * @extends Roo.Toolbar.Item
27134 * A simple class that renders text directly into a toolbar.
27136 * Creates a new TextItem
27137 * @param {String} text
27139 Roo.Toolbar.TextItem = function(text){
27140 if (typeof(text) == 'object') {
27143 var s = document.createElement("span");
27144 s.className = "ytb-text";
27145 s.innerHTML = text;
27146 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27148 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27149 enable:Roo.emptyFn,
27150 disable:Roo.emptyFn,
27155 * @class Roo.Toolbar.Button
27156 * @extends Roo.Button
27157 * A button that renders into a toolbar.
27159 * Creates a new Button
27160 * @param {Object} config A standard {@link Roo.Button} config object
27162 Roo.Toolbar.Button = function(config){
27163 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27165 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27166 render : function(td){
27168 Roo.Toolbar.Button.superclass.render.call(this, td);
27172 * Removes and destroys this button
27174 destroy : function(){
27175 Roo.Toolbar.Button.superclass.destroy.call(this);
27176 this.td.parentNode.removeChild(this.td);
27180 * Shows this button
27183 this.hidden = false;
27184 this.td.style.display = "";
27188 * Hides this button
27191 this.hidden = true;
27192 this.td.style.display = "none";
27196 * Disables this item
27198 disable : function(){
27199 Roo.fly(this.td).addClass("x-item-disabled");
27200 this.disabled = true;
27204 * Enables this item
27206 enable : function(){
27207 Roo.fly(this.td).removeClass("x-item-disabled");
27208 this.disabled = false;
27211 // backwards compat
27212 Roo.ToolbarButton = Roo.Toolbar.Button;
27215 * @class Roo.Toolbar.SplitButton
27216 * @extends Roo.SplitButton
27217 * A menu button that renders into a toolbar.
27219 * Creates a new SplitButton
27220 * @param {Object} config A standard {@link Roo.SplitButton} config object
27222 Roo.Toolbar.SplitButton = function(config){
27223 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27225 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27226 render : function(td){
27228 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27232 * Removes and destroys this button
27234 destroy : function(){
27235 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27236 this.td.parentNode.removeChild(this.td);
27240 * Shows this button
27243 this.hidden = false;
27244 this.td.style.display = "";
27248 * Hides this button
27251 this.hidden = true;
27252 this.td.style.display = "none";
27256 // backwards compat
27257 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27259 * Ext JS Library 1.1.1
27260 * Copyright(c) 2006-2007, Ext JS, LLC.
27262 * Originally Released Under LGPL - original licence link has changed is not relivant.
27265 * <script type="text/javascript">
27269 * @class Roo.PagingToolbar
27270 * @extends Roo.Toolbar
27271 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27273 * Create a new PagingToolbar
27274 * @param {Object} config The config object
27276 Roo.PagingToolbar = function(el, ds, config)
27278 // old args format still supported... - xtype is prefered..
27279 if (typeof(el) == 'object' && el.xtype) {
27280 // created from xtype...
27282 ds = el.dataSource;
27283 el = config.container;
27286 if (config.items) {
27287 items = config.items;
27291 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27294 this.renderButtons(this.el);
27297 // supprot items array.
27299 Roo.each(items, function(e) {
27300 this.add(Roo.factory(e));
27305 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27307 * @cfg {Roo.data.Store} dataSource
27308 * The underlying data store providing the paged data
27311 * @cfg {String/HTMLElement/Element} container
27312 * container The id or element that will contain the toolbar
27315 * @cfg {Boolean} displayInfo
27316 * True to display the displayMsg (defaults to false)
27319 * @cfg {Number} pageSize
27320 * The number of records to display per page (defaults to 20)
27324 * @cfg {String} displayMsg
27325 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27327 displayMsg : 'Displaying {0} - {1} of {2}',
27329 * @cfg {String} emptyMsg
27330 * The message to display when no records are found (defaults to "No data to display")
27332 emptyMsg : 'No data to display',
27334 * Customizable piece of the default paging text (defaults to "Page")
27337 beforePageText : "Page",
27339 * Customizable piece of the default paging text (defaults to "of %0")
27342 afterPageText : "of {0}",
27344 * Customizable piece of the default paging text (defaults to "First Page")
27347 firstText : "First Page",
27349 * Customizable piece of the default paging text (defaults to "Previous Page")
27352 prevText : "Previous Page",
27354 * Customizable piece of the default paging text (defaults to "Next Page")
27357 nextText : "Next Page",
27359 * Customizable piece of the default paging text (defaults to "Last Page")
27362 lastText : "Last Page",
27364 * Customizable piece of the default paging text (defaults to "Refresh")
27367 refreshText : "Refresh",
27370 renderButtons : function(el){
27371 Roo.PagingToolbar.superclass.render.call(this, el);
27372 this.first = this.addButton({
27373 tooltip: this.firstText,
27374 cls: "x-btn-icon x-grid-page-first",
27376 handler: this.onClick.createDelegate(this, ["first"])
27378 this.prev = this.addButton({
27379 tooltip: this.prevText,
27380 cls: "x-btn-icon x-grid-page-prev",
27382 handler: this.onClick.createDelegate(this, ["prev"])
27384 //this.addSeparator();
27385 this.add(this.beforePageText);
27386 this.field = Roo.get(this.addDom({
27391 cls: "x-grid-page-number"
27393 this.field.on("keydown", this.onPagingKeydown, this);
27394 this.field.on("focus", function(){this.dom.select();});
27395 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27396 this.field.setHeight(18);
27397 //this.addSeparator();
27398 this.next = this.addButton({
27399 tooltip: this.nextText,
27400 cls: "x-btn-icon x-grid-page-next",
27402 handler: this.onClick.createDelegate(this, ["next"])
27404 this.last = this.addButton({
27405 tooltip: this.lastText,
27406 cls: "x-btn-icon x-grid-page-last",
27408 handler: this.onClick.createDelegate(this, ["last"])
27410 //this.addSeparator();
27411 this.loading = this.addButton({
27412 tooltip: this.refreshText,
27413 cls: "x-btn-icon x-grid-loading",
27414 handler: this.onClick.createDelegate(this, ["refresh"])
27417 if(this.displayInfo){
27418 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27423 updateInfo : function(){
27424 if(this.displayEl){
27425 var count = this.ds.getCount();
27426 var msg = count == 0 ?
27430 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27432 this.displayEl.update(msg);
27437 onLoad : function(ds, r, o){
27438 this.cursor = o.params ? o.params.start : 0;
27439 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27441 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27442 this.field.dom.value = ap;
27443 this.first.setDisabled(ap == 1);
27444 this.prev.setDisabled(ap == 1);
27445 this.next.setDisabled(ap == ps);
27446 this.last.setDisabled(ap == ps);
27447 this.loading.enable();
27452 getPageData : function(){
27453 var total = this.ds.getTotalCount();
27456 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27457 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27462 onLoadError : function(){
27463 this.loading.enable();
27467 onPagingKeydown : function(e){
27468 var k = e.getKey();
27469 var d = this.getPageData();
27471 var v = this.field.dom.value, pageNum;
27472 if(!v || isNaN(pageNum = parseInt(v, 10))){
27473 this.field.dom.value = d.activePage;
27476 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27477 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27480 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))
27482 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27483 this.field.dom.value = pageNum;
27484 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27487 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27489 var v = this.field.dom.value, pageNum;
27490 var increment = (e.shiftKey) ? 10 : 1;
27491 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27493 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27494 this.field.dom.value = d.activePage;
27497 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27499 this.field.dom.value = parseInt(v, 10) + increment;
27500 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27501 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27508 beforeLoad : function(){
27510 this.loading.disable();
27515 onClick : function(which){
27519 ds.load({params:{start: 0, limit: this.pageSize}});
27522 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27525 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27528 var total = ds.getTotalCount();
27529 var extra = total % this.pageSize;
27530 var lastStart = extra ? (total - extra) : total-this.pageSize;
27531 ds.load({params:{start: lastStart, limit: this.pageSize}});
27534 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27540 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27541 * @param {Roo.data.Store} store The data store to unbind
27543 unbind : function(ds){
27544 ds.un("beforeload", this.beforeLoad, this);
27545 ds.un("load", this.onLoad, this);
27546 ds.un("loadexception", this.onLoadError, this);
27547 ds.un("remove", this.updateInfo, this);
27548 ds.un("add", this.updateInfo, this);
27549 this.ds = undefined;
27553 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27554 * @param {Roo.data.Store} store The data store to bind
27556 bind : function(ds){
27557 ds.on("beforeload", this.beforeLoad, this);
27558 ds.on("load", this.onLoad, this);
27559 ds.on("loadexception", this.onLoadError, this);
27560 ds.on("remove", this.updateInfo, this);
27561 ds.on("add", this.updateInfo, this);
27566 * Ext JS Library 1.1.1
27567 * Copyright(c) 2006-2007, Ext JS, LLC.
27569 * Originally Released Under LGPL - original licence link has changed is not relivant.
27572 * <script type="text/javascript">
27576 * @class Roo.Resizable
27577 * @extends Roo.util.Observable
27578 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27579 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27580 * 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
27581 * the element will be wrapped for you automatically.</p>
27582 * <p>Here is the list of valid resize handles:</p>
27585 ------ -------------------
27594 'hd' horizontal drag
27597 * <p>Here's an example showing the creation of a typical Resizable:</p>
27599 var resizer = new Roo.Resizable("element-id", {
27607 resizer.on("resize", myHandler);
27609 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27610 * resizer.east.setDisplayed(false);</p>
27611 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27612 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27613 * resize operation's new size (defaults to [0, 0])
27614 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27615 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27616 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27617 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27618 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27619 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27620 * @cfg {Number} width The width of the element in pixels (defaults to null)
27621 * @cfg {Number} height The height of the element in pixels (defaults to null)
27622 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27623 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27624 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27625 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27626 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27627 * in favor of the handles config option (defaults to false)
27628 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27629 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27630 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27631 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27632 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27633 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27634 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27635 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27636 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27637 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27638 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27640 * Create a new resizable component
27641 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27642 * @param {Object} config configuration options
27644 Roo.Resizable = function(el, config)
27646 this.el = Roo.get(el);
27648 if(config && config.wrap){
27649 config.resizeChild = this.el;
27650 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27651 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27652 this.el.setStyle("overflow", "hidden");
27653 this.el.setPositioning(config.resizeChild.getPositioning());
27654 config.resizeChild.clearPositioning();
27655 if(!config.width || !config.height){
27656 var csize = config.resizeChild.getSize();
27657 this.el.setSize(csize.width, csize.height);
27659 if(config.pinned && !config.adjustments){
27660 config.adjustments = "auto";
27664 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27665 this.proxy.unselectable();
27666 this.proxy.enableDisplayMode('block');
27668 Roo.apply(this, config);
27671 this.disableTrackOver = true;
27672 this.el.addClass("x-resizable-pinned");
27674 // if the element isn't positioned, make it relative
27675 var position = this.el.getStyle("position");
27676 if(position != "absolute" && position != "fixed"){
27677 this.el.setStyle("position", "relative");
27679 if(!this.handles){ // no handles passed, must be legacy style
27680 this.handles = 's,e,se';
27681 if(this.multiDirectional){
27682 this.handles += ',n,w';
27685 if(this.handles == "all"){
27686 this.handles = "n s e w ne nw se sw";
27688 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27689 var ps = Roo.Resizable.positions;
27690 for(var i = 0, len = hs.length; i < len; i++){
27691 if(hs[i] && ps[hs[i]]){
27692 var pos = ps[hs[i]];
27693 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27697 this.corner = this.southeast;
27699 // updateBox = the box can move..
27700 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27701 this.updateBox = true;
27704 this.activeHandle = null;
27706 if(this.resizeChild){
27707 if(typeof this.resizeChild == "boolean"){
27708 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27710 this.resizeChild = Roo.get(this.resizeChild, true);
27714 if(this.adjustments == "auto"){
27715 var rc = this.resizeChild;
27716 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27717 if(rc && (hw || hn)){
27718 rc.position("relative");
27719 rc.setLeft(hw ? hw.el.getWidth() : 0);
27720 rc.setTop(hn ? hn.el.getHeight() : 0);
27722 this.adjustments = [
27723 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27724 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27728 if(this.draggable){
27729 this.dd = this.dynamic ?
27730 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27731 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27737 * @event beforeresize
27738 * Fired before resize is allowed. Set enabled to false to cancel resize.
27739 * @param {Roo.Resizable} this
27740 * @param {Roo.EventObject} e The mousedown event
27742 "beforeresize" : true,
27745 * Fired after a resize.
27746 * @param {Roo.Resizable} this
27747 * @param {Number} width The new width
27748 * @param {Number} height The new height
27749 * @param {Roo.EventObject} e The mouseup event
27754 if(this.width !== null && this.height !== null){
27755 this.resizeTo(this.width, this.height);
27757 this.updateChildSize();
27760 this.el.dom.style.zoom = 1;
27762 Roo.Resizable.superclass.constructor.call(this);
27765 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27766 resizeChild : false,
27767 adjustments : [0, 0],
27777 multiDirectional : false,
27778 disableTrackOver : false,
27779 easing : 'easeOutStrong',
27780 widthIncrement : 0,
27781 heightIncrement : 0,
27785 preserveRatio : false,
27786 transparent: false,
27792 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27794 constrainTo: undefined,
27796 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27798 resizeRegion: undefined,
27802 * Perform a manual resize
27803 * @param {Number} width
27804 * @param {Number} height
27806 resizeTo : function(width, height){
27807 this.el.setSize(width, height);
27808 this.updateChildSize();
27809 this.fireEvent("resize", this, width, height, null);
27813 startSizing : function(e, handle){
27814 this.fireEvent("beforeresize", this, e);
27815 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27818 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27819 this.overlay.unselectable();
27820 this.overlay.enableDisplayMode("block");
27821 this.overlay.on("mousemove", this.onMouseMove, this);
27822 this.overlay.on("mouseup", this.onMouseUp, this);
27824 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27826 this.resizing = true;
27827 this.startBox = this.el.getBox();
27828 this.startPoint = e.getXY();
27829 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27830 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27832 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27833 this.overlay.show();
27835 if(this.constrainTo) {
27836 var ct = Roo.get(this.constrainTo);
27837 this.resizeRegion = ct.getRegion().adjust(
27838 ct.getFrameWidth('t'),
27839 ct.getFrameWidth('l'),
27840 -ct.getFrameWidth('b'),
27841 -ct.getFrameWidth('r')
27845 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27847 this.proxy.setBox(this.startBox);
27849 this.proxy.setStyle('visibility', 'visible');
27855 onMouseDown : function(handle, e){
27858 this.activeHandle = handle;
27859 this.startSizing(e, handle);
27864 onMouseUp : function(e){
27865 var size = this.resizeElement();
27866 this.resizing = false;
27868 this.overlay.hide();
27870 this.fireEvent("resize", this, size.width, size.height, e);
27874 updateChildSize : function(){
27875 if(this.resizeChild){
27877 var child = this.resizeChild;
27878 var adj = this.adjustments;
27879 if(el.dom.offsetWidth){
27880 var b = el.getSize(true);
27881 child.setSize(b.width+adj[0], b.height+adj[1]);
27883 // Second call here for IE
27884 // The first call enables instant resizing and
27885 // the second call corrects scroll bars if they
27888 setTimeout(function(){
27889 if(el.dom.offsetWidth){
27890 var b = el.getSize(true);
27891 child.setSize(b.width+adj[0], b.height+adj[1]);
27899 snap : function(value, inc, min){
27900 if(!inc || !value) return value;
27901 var newValue = value;
27902 var m = value % inc;
27905 newValue = value + (inc-m);
27907 newValue = value - m;
27910 return Math.max(min, newValue);
27914 resizeElement : function(){
27915 var box = this.proxy.getBox();
27916 if(this.updateBox){
27917 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27919 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27921 this.updateChildSize();
27929 constrain : function(v, diff, m, mx){
27932 }else if(v - diff > mx){
27939 onMouseMove : function(e){
27941 try{// try catch so if something goes wrong the user doesn't get hung
27943 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27947 //var curXY = this.startPoint;
27948 var curSize = this.curSize || this.startBox;
27949 var x = this.startBox.x, y = this.startBox.y;
27950 var ox = x, oy = y;
27951 var w = curSize.width, h = curSize.height;
27952 var ow = w, oh = h;
27953 var mw = this.minWidth, mh = this.minHeight;
27954 var mxw = this.maxWidth, mxh = this.maxHeight;
27955 var wi = this.widthIncrement;
27956 var hi = this.heightIncrement;
27958 var eventXY = e.getXY();
27959 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27960 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27962 var pos = this.activeHandle.position;
27967 w = Math.min(Math.max(mw, w), mxw);
27972 h = Math.min(Math.max(mh, h), mxh);
27977 w = Math.min(Math.max(mw, w), mxw);
27978 h = Math.min(Math.max(mh, h), mxh);
27981 diffY = this.constrain(h, diffY, mh, mxh);
27988 var adiffX = Math.abs(diffX);
27989 var sub = (adiffX % wi); // how much
27990 if (sub > (wi/2)) { // far enough to snap
27991 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27993 // remove difference..
27994 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27998 x = Math.max(this.minX, x);
28001 diffX = this.constrain(w, diffX, mw, mxw);
28007 w = Math.min(Math.max(mw, w), mxw);
28008 diffY = this.constrain(h, diffY, mh, mxh);
28013 diffX = this.constrain(w, diffX, mw, mxw);
28014 diffY = this.constrain(h, diffY, mh, mxh);
28021 diffX = this.constrain(w, diffX, mw, mxw);
28023 h = Math.min(Math.max(mh, h), mxh);
28029 var sw = this.snap(w, wi, mw);
28030 var sh = this.snap(h, hi, mh);
28031 if(sw != w || sh != h){
28054 if(this.preserveRatio){
28059 h = Math.min(Math.max(mh, h), mxh);
28064 w = Math.min(Math.max(mw, w), mxw);
28069 w = Math.min(Math.max(mw, w), mxw);
28075 w = Math.min(Math.max(mw, w), mxw);
28081 h = Math.min(Math.max(mh, h), mxh);
28089 h = Math.min(Math.max(mh, h), mxh);
28099 h = Math.min(Math.max(mh, h), mxh);
28107 if (pos == 'hdrag') {
28110 this.proxy.setBounds(x, y, w, h);
28112 this.resizeElement();
28119 handleOver : function(){
28121 this.el.addClass("x-resizable-over");
28126 handleOut : function(){
28127 if(!this.resizing){
28128 this.el.removeClass("x-resizable-over");
28133 * Returns the element this component is bound to.
28134 * @return {Roo.Element}
28136 getEl : function(){
28141 * Returns the resizeChild element (or null).
28142 * @return {Roo.Element}
28144 getResizeChild : function(){
28145 return this.resizeChild;
28149 * Destroys this resizable. If the element was wrapped and
28150 * removeEl is not true then the element remains.
28151 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28153 destroy : function(removeEl){
28154 this.proxy.remove();
28156 this.overlay.removeAllListeners();
28157 this.overlay.remove();
28159 var ps = Roo.Resizable.positions;
28161 if(typeof ps[k] != "function" && this[ps[k]]){
28162 var h = this[ps[k]];
28163 h.el.removeAllListeners();
28168 this.el.update("");
28175 // hash to map config positions to true positions
28176 Roo.Resizable.positions = {
28177 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28182 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28184 // only initialize the template if resizable is used
28185 var tpl = Roo.DomHelper.createTemplate(
28186 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28189 Roo.Resizable.Handle.prototype.tpl = tpl;
28191 this.position = pos;
28193 // show north drag fro topdra
28194 var handlepos = pos == 'hdrag' ? 'north' : pos;
28196 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28197 if (pos == 'hdrag') {
28198 this.el.setStyle('cursor', 'pointer');
28200 this.el.unselectable();
28202 this.el.setOpacity(0);
28204 this.el.on("mousedown", this.onMouseDown, this);
28205 if(!disableTrackOver){
28206 this.el.on("mouseover", this.onMouseOver, this);
28207 this.el.on("mouseout", this.onMouseOut, this);
28212 Roo.Resizable.Handle.prototype = {
28213 afterResize : function(rz){
28217 onMouseDown : function(e){
28218 this.rz.onMouseDown(this, e);
28221 onMouseOver : function(e){
28222 this.rz.handleOver(this, e);
28225 onMouseOut : function(e){
28226 this.rz.handleOut(this, e);
28230 * Ext JS Library 1.1.1
28231 * Copyright(c) 2006-2007, Ext JS, LLC.
28233 * Originally Released Under LGPL - original licence link has changed is not relivant.
28236 * <script type="text/javascript">
28240 * @class Roo.Editor
28241 * @extends Roo.Component
28242 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28244 * Create a new Editor
28245 * @param {Roo.form.Field} field The Field object (or descendant)
28246 * @param {Object} config The config object
28248 Roo.Editor = function(field, config){
28249 Roo.Editor.superclass.constructor.call(this, config);
28250 this.field = field;
28253 * @event beforestartedit
28254 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28255 * false from the handler of this event.
28256 * @param {Editor} this
28257 * @param {Roo.Element} boundEl The underlying element bound to this editor
28258 * @param {Mixed} value The field value being set
28260 "beforestartedit" : true,
28263 * Fires when this editor is displayed
28264 * @param {Roo.Element} boundEl The underlying element bound to this editor
28265 * @param {Mixed} value The starting field value
28267 "startedit" : true,
28269 * @event beforecomplete
28270 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28271 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28272 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28273 * event will not fire since no edit actually occurred.
28274 * @param {Editor} this
28275 * @param {Mixed} value The current field value
28276 * @param {Mixed} startValue The original field value
28278 "beforecomplete" : true,
28281 * Fires after editing is complete and any changed value has been written to the underlying field.
28282 * @param {Editor} this
28283 * @param {Mixed} value The current field value
28284 * @param {Mixed} startValue The original field value
28288 * @event specialkey
28289 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28290 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28291 * @param {Roo.form.Field} this
28292 * @param {Roo.EventObject} e The event object
28294 "specialkey" : true
28298 Roo.extend(Roo.Editor, Roo.Component, {
28300 * @cfg {Boolean/String} autosize
28301 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28302 * or "height" to adopt the height only (defaults to false)
28305 * @cfg {Boolean} revertInvalid
28306 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28307 * validation fails (defaults to true)
28310 * @cfg {Boolean} ignoreNoChange
28311 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28312 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28313 * will never be ignored.
28316 * @cfg {Boolean} hideEl
28317 * False to keep the bound element visible while the editor is displayed (defaults to true)
28320 * @cfg {Mixed} value
28321 * The data value of the underlying field (defaults to "")
28325 * @cfg {String} alignment
28326 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28330 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28331 * for bottom-right shadow (defaults to "frame")
28335 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28339 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28341 completeOnEnter : false,
28343 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28345 cancelOnEsc : false,
28347 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28352 onRender : function(ct, position){
28353 this.el = new Roo.Layer({
28354 shadow: this.shadow,
28360 constrain: this.constrain
28362 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28363 if(this.field.msgTarget != 'title'){
28364 this.field.msgTarget = 'qtip';
28366 this.field.render(this.el);
28368 this.field.el.dom.setAttribute('autocomplete', 'off');
28370 this.field.on("specialkey", this.onSpecialKey, this);
28371 if(this.swallowKeys){
28372 this.field.el.swallowEvent(['keydown','keypress']);
28375 this.field.on("blur", this.onBlur, this);
28376 if(this.field.grow){
28377 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28381 onSpecialKey : function(field, e)
28383 //Roo.log('editor onSpecialKey');
28384 if(this.completeOnEnter && e.getKey() == e.ENTER){
28386 this.completeEdit();
28389 // do not fire special key otherwise it might hide close the editor...
28390 if(e.getKey() == e.ENTER){
28393 if(this.cancelOnEsc && e.getKey() == e.ESC){
28397 this.fireEvent('specialkey', field, e);
28402 * Starts the editing process and shows the editor.
28403 * @param {String/HTMLElement/Element} el The element to edit
28404 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28405 * to the innerHTML of el.
28407 startEdit : function(el, value){
28409 this.completeEdit();
28411 this.boundEl = Roo.get(el);
28412 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28413 if(!this.rendered){
28414 this.render(this.parentEl || document.body);
28416 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28419 this.startValue = v;
28420 this.field.setValue(v);
28422 var sz = this.boundEl.getSize();
28423 switch(this.autoSize){
28425 this.setSize(sz.width, "");
28428 this.setSize("", sz.height);
28431 this.setSize(sz.width, sz.height);
28434 this.el.alignTo(this.boundEl, this.alignment);
28435 this.editing = true;
28437 Roo.QuickTips.disable();
28443 * Sets the height and width of this editor.
28444 * @param {Number} width The new width
28445 * @param {Number} height The new height
28447 setSize : function(w, h){
28448 this.field.setSize(w, h);
28455 * Realigns the editor to the bound field based on the current alignment config value.
28457 realign : function(){
28458 this.el.alignTo(this.boundEl, this.alignment);
28462 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28463 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28465 completeEdit : function(remainVisible){
28469 var v = this.getValue();
28470 if(this.revertInvalid !== false && !this.field.isValid()){
28471 v = this.startValue;
28472 this.cancelEdit(true);
28474 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28475 this.editing = false;
28479 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28480 this.editing = false;
28481 if(this.updateEl && this.boundEl){
28482 this.boundEl.update(v);
28484 if(remainVisible !== true){
28487 this.fireEvent("complete", this, v, this.startValue);
28492 onShow : function(){
28494 if(this.hideEl !== false){
28495 this.boundEl.hide();
28498 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28499 this.fixIEFocus = true;
28500 this.deferredFocus.defer(50, this);
28502 this.field.focus();
28504 this.fireEvent("startedit", this.boundEl, this.startValue);
28507 deferredFocus : function(){
28509 this.field.focus();
28514 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28515 * reverted to the original starting value.
28516 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28517 * cancel (defaults to false)
28519 cancelEdit : function(remainVisible){
28521 this.setValue(this.startValue);
28522 if(remainVisible !== true){
28529 onBlur : function(){
28530 if(this.allowBlur !== true && this.editing){
28531 this.completeEdit();
28536 onHide : function(){
28538 this.completeEdit();
28542 if(this.field.collapse){
28543 this.field.collapse();
28546 if(this.hideEl !== false){
28547 this.boundEl.show();
28550 Roo.QuickTips.enable();
28555 * Sets the data value of the editor
28556 * @param {Mixed} value Any valid value supported by the underlying field
28558 setValue : function(v){
28559 this.field.setValue(v);
28563 * Gets the data value of the editor
28564 * @return {Mixed} The data value
28566 getValue : function(){
28567 return this.field.getValue();
28571 * Ext JS Library 1.1.1
28572 * Copyright(c) 2006-2007, Ext JS, LLC.
28574 * Originally Released Under LGPL - original licence link has changed is not relivant.
28577 * <script type="text/javascript">
28581 * @class Roo.BasicDialog
28582 * @extends Roo.util.Observable
28583 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28585 var dlg = new Roo.BasicDialog("my-dlg", {
28594 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28595 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28596 dlg.addButton('Cancel', dlg.hide, dlg);
28599 <b>A Dialog should always be a direct child of the body element.</b>
28600 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28601 * @cfg {String} title Default text to display in the title bar (defaults to null)
28602 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28603 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28604 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28605 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28606 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28607 * (defaults to null with no animation)
28608 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28609 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28610 * property for valid values (defaults to 'all')
28611 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28612 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28613 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28614 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28615 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28616 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28617 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28618 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28619 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28620 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28621 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28622 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28623 * draggable = true (defaults to false)
28624 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28625 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28626 * shadow (defaults to false)
28627 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28628 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28629 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28630 * @cfg {Array} buttons Array of buttons
28631 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28633 * Create a new BasicDialog.
28634 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28635 * @param {Object} config Configuration options
28637 Roo.BasicDialog = function(el, config){
28638 this.el = Roo.get(el);
28639 var dh = Roo.DomHelper;
28640 if(!this.el && config && config.autoCreate){
28641 if(typeof config.autoCreate == "object"){
28642 if(!config.autoCreate.id){
28643 config.autoCreate.id = el;
28645 this.el = dh.append(document.body,
28646 config.autoCreate, true);
28648 this.el = dh.append(document.body,
28649 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28653 el.setDisplayed(true);
28654 el.hide = this.hideAction;
28656 el.addClass("x-dlg");
28658 Roo.apply(this, config);
28660 this.proxy = el.createProxy("x-dlg-proxy");
28661 this.proxy.hide = this.hideAction;
28662 this.proxy.setOpacity(.5);
28666 el.setWidth(config.width);
28669 el.setHeight(config.height);
28671 this.size = el.getSize();
28672 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28673 this.xy = [config.x,config.y];
28675 this.xy = el.getCenterXY(true);
28677 /** The header element @type Roo.Element */
28678 this.header = el.child("> .x-dlg-hd");
28679 /** The body element @type Roo.Element */
28680 this.body = el.child("> .x-dlg-bd");
28681 /** The footer element @type Roo.Element */
28682 this.footer = el.child("> .x-dlg-ft");
28685 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28688 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28691 this.header.unselectable();
28693 this.header.update(this.title);
28695 // this element allows the dialog to be focused for keyboard event
28696 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28697 this.focusEl.swallowEvent("click", true);
28699 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28701 // wrap the body and footer for special rendering
28702 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28704 this.bwrap.dom.appendChild(this.footer.dom);
28707 this.bg = this.el.createChild({
28708 tag: "div", cls:"x-dlg-bg",
28709 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28711 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28714 if(this.autoScroll !== false && !this.autoTabs){
28715 this.body.setStyle("overflow", "auto");
28718 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28720 if(this.closable !== false){
28721 this.el.addClass("x-dlg-closable");
28722 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28723 this.close.on("click", this.closeClick, this);
28724 this.close.addClassOnOver("x-dlg-close-over");
28726 if(this.collapsible !== false){
28727 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28728 this.collapseBtn.on("click", this.collapseClick, this);
28729 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28730 this.header.on("dblclick", this.collapseClick, this);
28732 if(this.resizable !== false){
28733 this.el.addClass("x-dlg-resizable");
28734 this.resizer = new Roo.Resizable(el, {
28735 minWidth: this.minWidth || 80,
28736 minHeight:this.minHeight || 80,
28737 handles: this.resizeHandles || "all",
28740 this.resizer.on("beforeresize", this.beforeResize, this);
28741 this.resizer.on("resize", this.onResize, this);
28743 if(this.draggable !== false){
28744 el.addClass("x-dlg-draggable");
28745 if (!this.proxyDrag) {
28746 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28749 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28751 dd.setHandleElId(this.header.id);
28752 dd.endDrag = this.endMove.createDelegate(this);
28753 dd.startDrag = this.startMove.createDelegate(this);
28754 dd.onDrag = this.onDrag.createDelegate(this);
28759 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28760 this.mask.enableDisplayMode("block");
28762 this.el.addClass("x-dlg-modal");
28765 this.shadow = new Roo.Shadow({
28766 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28767 offset : this.shadowOffset
28770 this.shadowOffset = 0;
28772 if(Roo.useShims && this.shim !== false){
28773 this.shim = this.el.createShim();
28774 this.shim.hide = this.hideAction;
28782 if (this.buttons) {
28783 var bts= this.buttons;
28785 Roo.each(bts, function(b) {
28794 * Fires when a key is pressed
28795 * @param {Roo.BasicDialog} this
28796 * @param {Roo.EventObject} e
28801 * Fires when this dialog is moved by the user.
28802 * @param {Roo.BasicDialog} this
28803 * @param {Number} x The new page X
28804 * @param {Number} y The new page Y
28809 * Fires when this dialog is resized by the user.
28810 * @param {Roo.BasicDialog} this
28811 * @param {Number} width The new width
28812 * @param {Number} height The new height
28816 * @event beforehide
28817 * Fires before this dialog is hidden.
28818 * @param {Roo.BasicDialog} this
28820 "beforehide" : true,
28823 * Fires when this dialog is hidden.
28824 * @param {Roo.BasicDialog} this
28828 * @event beforeshow
28829 * Fires before this dialog is shown.
28830 * @param {Roo.BasicDialog} this
28832 "beforeshow" : true,
28835 * Fires when this dialog is shown.
28836 * @param {Roo.BasicDialog} this
28840 el.on("keydown", this.onKeyDown, this);
28841 el.on("mousedown", this.toFront, this);
28842 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28844 Roo.DialogManager.register(this);
28845 Roo.BasicDialog.superclass.constructor.call(this);
28848 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28849 shadowOffset: Roo.isIE ? 6 : 5,
28852 minButtonWidth: 75,
28853 defaultButton: null,
28854 buttonAlign: "right",
28859 * Sets the dialog title text
28860 * @param {String} text The title text to display
28861 * @return {Roo.BasicDialog} this
28863 setTitle : function(text){
28864 this.header.update(text);
28869 closeClick : function(){
28874 collapseClick : function(){
28875 this[this.collapsed ? "expand" : "collapse"]();
28879 * Collapses the dialog to its minimized state (only the title bar is visible).
28880 * Equivalent to the user clicking the collapse dialog button.
28882 collapse : function(){
28883 if(!this.collapsed){
28884 this.collapsed = true;
28885 this.el.addClass("x-dlg-collapsed");
28886 this.restoreHeight = this.el.getHeight();
28887 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28892 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28893 * clicking the expand dialog button.
28895 expand : function(){
28896 if(this.collapsed){
28897 this.collapsed = false;
28898 this.el.removeClass("x-dlg-collapsed");
28899 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28904 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28905 * @return {Roo.TabPanel} The tabs component
28907 initTabs : function(){
28908 var tabs = this.getTabs();
28909 while(tabs.getTab(0)){
28912 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28914 tabs.addTab(Roo.id(dom), dom.title);
28922 beforeResize : function(){
28923 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28927 onResize : function(){
28928 this.refreshSize();
28929 this.syncBodyHeight();
28930 this.adjustAssets();
28932 this.fireEvent("resize", this, this.size.width, this.size.height);
28936 onKeyDown : function(e){
28937 if(this.isVisible()){
28938 this.fireEvent("keydown", this, e);
28943 * Resizes the dialog.
28944 * @param {Number} width
28945 * @param {Number} height
28946 * @return {Roo.BasicDialog} this
28948 resizeTo : function(width, height){
28949 this.el.setSize(width, height);
28950 this.size = {width: width, height: height};
28951 this.syncBodyHeight();
28952 if(this.fixedcenter){
28955 if(this.isVisible()){
28956 this.constrainXY();
28957 this.adjustAssets();
28959 this.fireEvent("resize", this, width, height);
28965 * Resizes the dialog to fit the specified content size.
28966 * @param {Number} width
28967 * @param {Number} height
28968 * @return {Roo.BasicDialog} this
28970 setContentSize : function(w, h){
28971 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28972 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28973 //if(!this.el.isBorderBox()){
28974 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28975 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28978 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28979 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28981 this.resizeTo(w, h);
28986 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28987 * executed in response to a particular key being pressed while the dialog is active.
28988 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28989 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28990 * @param {Function} fn The function to call
28991 * @param {Object} scope (optional) The scope of the function
28992 * @return {Roo.BasicDialog} this
28994 addKeyListener : function(key, fn, scope){
28995 var keyCode, shift, ctrl, alt;
28996 if(typeof key == "object" && !(key instanceof Array)){
28997 keyCode = key["key"];
28998 shift = key["shift"];
28999 ctrl = key["ctrl"];
29004 var handler = function(dlg, e){
29005 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29006 var k = e.getKey();
29007 if(keyCode instanceof Array){
29008 for(var i = 0, len = keyCode.length; i < len; i++){
29009 if(keyCode[i] == k){
29010 fn.call(scope || window, dlg, k, e);
29016 fn.call(scope || window, dlg, k, e);
29021 this.on("keydown", handler);
29026 * Returns the TabPanel component (creates it if it doesn't exist).
29027 * Note: If you wish to simply check for the existence of tabs without creating them,
29028 * check for a null 'tabs' property.
29029 * @return {Roo.TabPanel} The tabs component
29031 getTabs : function(){
29033 this.el.addClass("x-dlg-auto-tabs");
29034 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29035 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29041 * Adds a button to the footer section of the dialog.
29042 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29043 * object or a valid Roo.DomHelper element config
29044 * @param {Function} handler The function called when the button is clicked
29045 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29046 * @return {Roo.Button} The new button
29048 addButton : function(config, handler, scope){
29049 var dh = Roo.DomHelper;
29051 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29053 if(!this.btnContainer){
29054 var tb = this.footer.createChild({
29056 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29057 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29059 this.btnContainer = tb.firstChild.firstChild.firstChild;
29064 minWidth: this.minButtonWidth,
29067 if(typeof config == "string"){
29068 bconfig.text = config;
29071 bconfig.dhconfig = config;
29073 Roo.apply(bconfig, config);
29077 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29078 bconfig.position = Math.max(0, bconfig.position);
29079 fc = this.btnContainer.childNodes[bconfig.position];
29082 var btn = new Roo.Button(
29084 this.btnContainer.insertBefore(document.createElement("td"),fc)
29085 : this.btnContainer.appendChild(document.createElement("td")),
29086 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29089 this.syncBodyHeight();
29092 * Array of all the buttons that have been added to this dialog via addButton
29097 this.buttons.push(btn);
29102 * Sets the default button to be focused when the dialog is displayed.
29103 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29104 * @return {Roo.BasicDialog} this
29106 setDefaultButton : function(btn){
29107 this.defaultButton = btn;
29112 getHeaderFooterHeight : function(safe){
29115 height += this.header.getHeight();
29118 var fm = this.footer.getMargins();
29119 height += (this.footer.getHeight()+fm.top+fm.bottom);
29121 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29122 height += this.centerBg.getPadding("tb");
29127 syncBodyHeight : function(){
29128 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29129 var height = this.size.height - this.getHeaderFooterHeight(false);
29130 bd.setHeight(height-bd.getMargins("tb"));
29131 var hh = this.header.getHeight();
29132 var h = this.size.height-hh;
29134 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29135 bw.setHeight(h-cb.getPadding("tb"));
29136 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29137 bd.setWidth(bw.getWidth(true));
29139 this.tabs.syncHeight();
29141 this.tabs.el.repaint();
29147 * Restores the previous state of the dialog if Roo.state is configured.
29148 * @return {Roo.BasicDialog} this
29150 restoreState : function(){
29151 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29152 if(box && box.width){
29153 this.xy = [box.x, box.y];
29154 this.resizeTo(box.width, box.height);
29160 beforeShow : function(){
29162 if(this.fixedcenter){
29163 this.xy = this.el.getCenterXY(true);
29166 Roo.get(document.body).addClass("x-body-masked");
29167 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29170 this.constrainXY();
29174 animShow : function(){
29175 var b = Roo.get(this.animateTarget).getBox();
29176 this.proxy.setSize(b.width, b.height);
29177 this.proxy.setLocation(b.x, b.y);
29179 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29180 true, .35, this.showEl.createDelegate(this));
29184 * Shows the dialog.
29185 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29186 * @return {Roo.BasicDialog} this
29188 show : function(animateTarget){
29189 if (this.fireEvent("beforeshow", this) === false){
29192 if(this.syncHeightBeforeShow){
29193 this.syncBodyHeight();
29194 }else if(this.firstShow){
29195 this.firstShow = false;
29196 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29198 this.animateTarget = animateTarget || this.animateTarget;
29199 if(!this.el.isVisible()){
29201 if(this.animateTarget && Roo.get(this.animateTarget)){
29211 showEl : function(){
29213 this.el.setXY(this.xy);
29215 this.adjustAssets(true);
29218 // IE peekaboo bug - fix found by Dave Fenwick
29222 this.fireEvent("show", this);
29226 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29227 * dialog itself will receive focus.
29229 focus : function(){
29230 if(this.defaultButton){
29231 this.defaultButton.focus();
29233 this.focusEl.focus();
29238 constrainXY : function(){
29239 if(this.constraintoviewport !== false){
29240 if(!this.viewSize){
29241 if(this.container){
29242 var s = this.container.getSize();
29243 this.viewSize = [s.width, s.height];
29245 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29248 var s = Roo.get(this.container||document).getScroll();
29250 var x = this.xy[0], y = this.xy[1];
29251 var w = this.size.width, h = this.size.height;
29252 var vw = this.viewSize[0], vh = this.viewSize[1];
29253 // only move it if it needs it
29255 // first validate right/bottom
29256 if(x + w > vw+s.left){
29260 if(y + h > vh+s.top){
29264 // then make sure top/left isn't negative
29276 if(this.isVisible()){
29277 this.el.setLocation(x, y);
29278 this.adjustAssets();
29285 onDrag : function(){
29286 if(!this.proxyDrag){
29287 this.xy = this.el.getXY();
29288 this.adjustAssets();
29293 adjustAssets : function(doShow){
29294 var x = this.xy[0], y = this.xy[1];
29295 var w = this.size.width, h = this.size.height;
29296 if(doShow === true){
29298 this.shadow.show(this.el);
29304 if(this.shadow && this.shadow.isVisible()){
29305 this.shadow.show(this.el);
29307 if(this.shim && this.shim.isVisible()){
29308 this.shim.setBounds(x, y, w, h);
29313 adjustViewport : function(w, h){
29315 w = Roo.lib.Dom.getViewWidth();
29316 h = Roo.lib.Dom.getViewHeight();
29319 this.viewSize = [w, h];
29320 if(this.modal && this.mask.isVisible()){
29321 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29322 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29324 if(this.isVisible()){
29325 this.constrainXY();
29330 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29331 * shadow, proxy, mask, etc.) Also removes all event listeners.
29332 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29334 destroy : function(removeEl){
29335 if(this.isVisible()){
29336 this.animateTarget = null;
29339 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29341 this.tabs.destroy(removeEl);
29354 for(var i = 0, len = this.buttons.length; i < len; i++){
29355 this.buttons[i].destroy();
29358 this.el.removeAllListeners();
29359 if(removeEl === true){
29360 this.el.update("");
29363 Roo.DialogManager.unregister(this);
29367 startMove : function(){
29368 if(this.proxyDrag){
29371 if(this.constraintoviewport !== false){
29372 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29377 endMove : function(){
29378 if(!this.proxyDrag){
29379 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29381 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29384 this.refreshSize();
29385 this.adjustAssets();
29387 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29391 * Brings this dialog to the front of any other visible dialogs
29392 * @return {Roo.BasicDialog} this
29394 toFront : function(){
29395 Roo.DialogManager.bringToFront(this);
29400 * Sends this dialog to the back (under) of any other visible dialogs
29401 * @return {Roo.BasicDialog} this
29403 toBack : function(){
29404 Roo.DialogManager.sendToBack(this);
29409 * Centers this dialog in the viewport
29410 * @return {Roo.BasicDialog} this
29412 center : function(){
29413 var xy = this.el.getCenterXY(true);
29414 this.moveTo(xy[0], xy[1]);
29419 * Moves the dialog's top-left corner to the specified point
29420 * @param {Number} x
29421 * @param {Number} y
29422 * @return {Roo.BasicDialog} this
29424 moveTo : function(x, y){
29426 if(this.isVisible()){
29427 this.el.setXY(this.xy);
29428 this.adjustAssets();
29434 * Aligns the dialog to the specified element
29435 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29436 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29437 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29438 * @return {Roo.BasicDialog} this
29440 alignTo : function(element, position, offsets){
29441 this.xy = this.el.getAlignToXY(element, position, offsets);
29442 if(this.isVisible()){
29443 this.el.setXY(this.xy);
29444 this.adjustAssets();
29450 * Anchors an element to another element and realigns it when the window is resized.
29451 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29452 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29453 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29454 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29455 * is a number, it is used as the buffer delay (defaults to 50ms).
29456 * @return {Roo.BasicDialog} this
29458 anchorTo : function(el, alignment, offsets, monitorScroll){
29459 var action = function(){
29460 this.alignTo(el, alignment, offsets);
29462 Roo.EventManager.onWindowResize(action, this);
29463 var tm = typeof monitorScroll;
29464 if(tm != 'undefined'){
29465 Roo.EventManager.on(window, 'scroll', action, this,
29466 {buffer: tm == 'number' ? monitorScroll : 50});
29473 * Returns true if the dialog is visible
29474 * @return {Boolean}
29476 isVisible : function(){
29477 return this.el.isVisible();
29481 animHide : function(callback){
29482 var b = Roo.get(this.animateTarget).getBox();
29484 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29486 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29487 this.hideEl.createDelegate(this, [callback]));
29491 * Hides the dialog.
29492 * @param {Function} callback (optional) Function to call when the dialog is hidden
29493 * @return {Roo.BasicDialog} this
29495 hide : function(callback){
29496 if (this.fireEvent("beforehide", this) === false){
29500 this.shadow.hide();
29505 // sometimes animateTarget seems to get set.. causing problems...
29506 // this just double checks..
29507 if(this.animateTarget && Roo.get(this.animateTarget)) {
29508 this.animHide(callback);
29511 this.hideEl(callback);
29517 hideEl : function(callback){
29521 Roo.get(document.body).removeClass("x-body-masked");
29523 this.fireEvent("hide", this);
29524 if(typeof callback == "function"){
29530 hideAction : function(){
29531 this.setLeft("-10000px");
29532 this.setTop("-10000px");
29533 this.setStyle("visibility", "hidden");
29537 refreshSize : function(){
29538 this.size = this.el.getSize();
29539 this.xy = this.el.getXY();
29540 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29544 // z-index is managed by the DialogManager and may be overwritten at any time
29545 setZIndex : function(index){
29547 this.mask.setStyle("z-index", index);
29550 this.shim.setStyle("z-index", ++index);
29553 this.shadow.setZIndex(++index);
29555 this.el.setStyle("z-index", ++index);
29557 this.proxy.setStyle("z-index", ++index);
29560 this.resizer.proxy.setStyle("z-index", ++index);
29563 this.lastZIndex = index;
29567 * Returns the element for this dialog
29568 * @return {Roo.Element} The underlying dialog Element
29570 getEl : function(){
29576 * @class Roo.DialogManager
29577 * Provides global access to BasicDialogs that have been created and
29578 * support for z-indexing (layering) multiple open dialogs.
29580 Roo.DialogManager = function(){
29582 var accessList = [];
29586 var sortDialogs = function(d1, d2){
29587 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29591 var orderDialogs = function(){
29592 accessList.sort(sortDialogs);
29593 var seed = Roo.DialogManager.zseed;
29594 for(var i = 0, len = accessList.length; i < len; i++){
29595 var dlg = accessList[i];
29597 dlg.setZIndex(seed + (i*10));
29604 * The starting z-index for BasicDialogs (defaults to 9000)
29605 * @type Number The z-index value
29610 register : function(dlg){
29611 list[dlg.id] = dlg;
29612 accessList.push(dlg);
29616 unregister : function(dlg){
29617 delete list[dlg.id];
29620 if(!accessList.indexOf){
29621 for( i = 0, len = accessList.length; i < len; i++){
29622 if(accessList[i] == dlg){
29623 accessList.splice(i, 1);
29628 i = accessList.indexOf(dlg);
29630 accessList.splice(i, 1);
29636 * Gets a registered dialog by id
29637 * @param {String/Object} id The id of the dialog or a dialog
29638 * @return {Roo.BasicDialog} this
29640 get : function(id){
29641 return typeof id == "object" ? id : list[id];
29645 * Brings the specified dialog to the front
29646 * @param {String/Object} dlg The id of the dialog or a dialog
29647 * @return {Roo.BasicDialog} this
29649 bringToFront : function(dlg){
29650 dlg = this.get(dlg);
29653 dlg._lastAccess = new Date().getTime();
29660 * Sends the specified dialog to the back
29661 * @param {String/Object} dlg The id of the dialog or a dialog
29662 * @return {Roo.BasicDialog} this
29664 sendToBack : function(dlg){
29665 dlg = this.get(dlg);
29666 dlg._lastAccess = -(new Date().getTime());
29672 * Hides all dialogs
29674 hideAll : function(){
29675 for(var id in list){
29676 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29685 * @class Roo.LayoutDialog
29686 * @extends Roo.BasicDialog
29687 * Dialog which provides adjustments for working with a layout in a Dialog.
29688 * Add your necessary layout config options to the dialog's config.<br>
29689 * Example usage (including a nested layout):
29692 dialog = new Roo.LayoutDialog("download-dlg", {
29701 // layout config merges with the dialog config
29703 tabPosition: "top",
29704 alwaysShowTabs: true
29707 dialog.addKeyListener(27, dialog.hide, dialog);
29708 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29709 dialog.addButton("Build It!", this.getDownload, this);
29711 // we can even add nested layouts
29712 var innerLayout = new Roo.BorderLayout("dl-inner", {
29722 innerLayout.beginUpdate();
29723 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29724 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29725 innerLayout.endUpdate(true);
29727 var layout = dialog.getLayout();
29728 layout.beginUpdate();
29729 layout.add("center", new Roo.ContentPanel("standard-panel",
29730 {title: "Download the Source", fitToFrame:true}));
29731 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29732 {title: "Build your own roo.js"}));
29733 layout.getRegion("center").showPanel(sp);
29734 layout.endUpdate();
29738 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29739 * @param {Object} config configuration options
29741 Roo.LayoutDialog = function(el, cfg){
29744 if (typeof(cfg) == 'undefined') {
29745 config = Roo.apply({}, el);
29746 // not sure why we use documentElement here.. - it should always be body.
29747 // IE7 borks horribly if we use documentElement.
29748 // webkit also does not like documentElement - it creates a body element...
29749 el = Roo.get( document.body || document.documentElement ).createChild();
29750 //config.autoCreate = true;
29754 config.autoTabs = false;
29755 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29756 this.body.setStyle({overflow:"hidden", position:"relative"});
29757 this.layout = new Roo.BorderLayout(this.body.dom, config);
29758 this.layout.monitorWindowResize = false;
29759 this.el.addClass("x-dlg-auto-layout");
29760 // fix case when center region overwrites center function
29761 this.center = Roo.BasicDialog.prototype.center;
29762 this.on("show", this.layout.layout, this.layout, true);
29763 if (config.items) {
29764 var xitems = config.items;
29765 delete config.items;
29766 Roo.each(xitems, this.addxtype, this);
29771 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29773 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29776 endUpdate : function(){
29777 this.layout.endUpdate();
29781 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29784 beginUpdate : function(){
29785 this.layout.beginUpdate();
29789 * Get the BorderLayout for this dialog
29790 * @return {Roo.BorderLayout}
29792 getLayout : function(){
29793 return this.layout;
29796 showEl : function(){
29797 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29799 this.layout.layout();
29804 // Use the syncHeightBeforeShow config option to control this automatically
29805 syncBodyHeight : function(){
29806 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29807 if(this.layout){this.layout.layout();}
29811 * Add an xtype element (actually adds to the layout.)
29812 * @return {Object} xdata xtype object data.
29815 addxtype : function(c) {
29816 return this.layout.addxtype(c);
29820 * Ext JS Library 1.1.1
29821 * Copyright(c) 2006-2007, Ext JS, LLC.
29823 * Originally Released Under LGPL - original licence link has changed is not relivant.
29826 * <script type="text/javascript">
29830 * @class Roo.MessageBox
29831 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29835 Roo.Msg.alert('Status', 'Changes saved successfully.');
29837 // Prompt for user data:
29838 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29840 // process text value...
29844 // Show a dialog using config options:
29846 title:'Save Changes?',
29847 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29848 buttons: Roo.Msg.YESNOCANCEL,
29855 Roo.MessageBox = function(){
29856 var dlg, opt, mask, waitTimer;
29857 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29858 var buttons, activeTextEl, bwidth;
29861 var handleButton = function(button){
29863 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29867 var handleHide = function(){
29868 if(opt && opt.cls){
29869 dlg.el.removeClass(opt.cls);
29872 Roo.TaskMgr.stop(waitTimer);
29878 var updateButtons = function(b){
29881 buttons["ok"].hide();
29882 buttons["cancel"].hide();
29883 buttons["yes"].hide();
29884 buttons["no"].hide();
29885 dlg.footer.dom.style.display = 'none';
29888 dlg.footer.dom.style.display = '';
29889 for(var k in buttons){
29890 if(typeof buttons[k] != "function"){
29893 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29894 width += buttons[k].el.getWidth()+15;
29904 var handleEsc = function(d, k, e){
29905 if(opt && opt.closable !== false){
29915 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29916 * @return {Roo.BasicDialog} The BasicDialog element
29918 getDialog : function(){
29920 dlg = new Roo.BasicDialog("x-msg-box", {
29925 constraintoviewport:false,
29927 collapsible : false,
29930 width:400, height:100,
29931 buttonAlign:"center",
29932 closeClick : function(){
29933 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29934 handleButton("no");
29936 handleButton("cancel");
29940 dlg.on("hide", handleHide);
29942 dlg.addKeyListener(27, handleEsc);
29944 var bt = this.buttonText;
29945 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29946 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29947 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29948 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29949 bodyEl = dlg.body.createChild({
29951 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>'
29953 msgEl = bodyEl.dom.firstChild;
29954 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29955 textboxEl.enableDisplayMode();
29956 textboxEl.addKeyListener([10,13], function(){
29957 if(dlg.isVisible() && opt && opt.buttons){
29958 if(opt.buttons.ok){
29959 handleButton("ok");
29960 }else if(opt.buttons.yes){
29961 handleButton("yes");
29965 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29966 textareaEl.enableDisplayMode();
29967 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29968 progressEl.enableDisplayMode();
29969 var pf = progressEl.dom.firstChild;
29971 pp = Roo.get(pf.firstChild);
29972 pp.setHeight(pf.offsetHeight);
29980 * Updates the message box body text
29981 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29982 * the XHTML-compliant non-breaking space character '&#160;')
29983 * @return {Roo.MessageBox} This message box
29985 updateText : function(text){
29986 if(!dlg.isVisible() && !opt.width){
29987 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29989 msgEl.innerHTML = text || ' ';
29990 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29991 Math.max(opt.minWidth || this.minWidth, bwidth));
29993 activeTextEl.setWidth(w);
29995 if(dlg.isVisible()){
29996 dlg.fixedcenter = false;
29998 dlg.setContentSize(w, bodyEl.getHeight());
29999 if(dlg.isVisible()){
30000 dlg.fixedcenter = true;
30006 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30007 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30008 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30009 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30010 * @return {Roo.MessageBox} This message box
30012 updateProgress : function(value, text){
30014 this.updateText(text);
30016 if (pp) { // weird bug on my firefox - for some reason this is not defined
30017 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30023 * Returns true if the message box is currently displayed
30024 * @return {Boolean} True if the message box is visible, else false
30026 isVisible : function(){
30027 return dlg && dlg.isVisible();
30031 * Hides the message box if it is displayed
30034 if(this.isVisible()){
30040 * Displays a new message box, or reinitializes an existing message box, based on the config options
30041 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30042 * The following config object properties are supported:
30044 Property Type Description
30045 ---------- --------------- ------------------------------------------------------------------------------------
30046 animEl String/Element An id or Element from which the message box should animate as it opens and
30047 closes (defaults to undefined)
30048 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30049 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30050 closable Boolean False to hide the top-right close button (defaults to true). Note that
30051 progress and wait dialogs will ignore this property and always hide the
30052 close button as they can only be closed programmatically.
30053 cls String A custom CSS class to apply to the message box element
30054 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30055 displayed (defaults to 75)
30056 fn Function A callback function to execute after closing the dialog. The arguments to the
30057 function will be btn (the name of the button that was clicked, if applicable,
30058 e.g. "ok"), and text (the value of the active text field, if applicable).
30059 Progress and wait dialogs will ignore this option since they do not respond to
30060 user actions and can only be closed programmatically, so any required function
30061 should be called by the same code after it closes the dialog.
30062 icon String A CSS class that provides a background image to be used as an icon for
30063 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30064 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30065 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30066 modal Boolean False to allow user interaction with the page while the message box is
30067 displayed (defaults to true)
30068 msg String A string that will replace the existing message box body text (defaults
30069 to the XHTML-compliant non-breaking space character ' ')
30070 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30071 progress Boolean True to display a progress bar (defaults to false)
30072 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30073 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30074 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30075 title String The title text
30076 value String The string value to set into the active textbox element if displayed
30077 wait Boolean True to display a progress bar (defaults to false)
30078 width Number The width of the dialog in pixels
30085 msg: 'Please enter your address:',
30087 buttons: Roo.MessageBox.OKCANCEL,
30090 animEl: 'addAddressBtn'
30093 * @param {Object} config Configuration options
30094 * @return {Roo.MessageBox} This message box
30096 show : function(options){
30097 if(this.isVisible()){
30100 var d = this.getDialog();
30102 d.setTitle(opt.title || " ");
30103 d.close.setDisplayed(opt.closable !== false);
30104 activeTextEl = textboxEl;
30105 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30110 textareaEl.setHeight(typeof opt.multiline == "number" ?
30111 opt.multiline : this.defaultTextHeight);
30112 activeTextEl = textareaEl;
30121 progressEl.setDisplayed(opt.progress === true);
30122 this.updateProgress(0);
30123 activeTextEl.dom.value = opt.value || "";
30125 dlg.setDefaultButton(activeTextEl);
30127 var bs = opt.buttons;
30130 db = buttons["ok"];
30131 }else if(bs && bs.yes){
30132 db = buttons["yes"];
30134 dlg.setDefaultButton(db);
30136 bwidth = updateButtons(opt.buttons);
30137 this.updateText(opt.msg);
30139 d.el.addClass(opt.cls);
30141 d.proxyDrag = opt.proxyDrag === true;
30142 d.modal = opt.modal !== false;
30143 d.mask = opt.modal !== false ? mask : false;
30144 if(!d.isVisible()){
30145 // force it to the end of the z-index stack so it gets a cursor in FF
30146 document.body.appendChild(dlg.el.dom);
30147 d.animateTarget = null;
30148 d.show(options.animEl);
30154 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30155 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30156 * and closing the message box when the process is complete.
30157 * @param {String} title The title bar text
30158 * @param {String} msg The message box body text
30159 * @return {Roo.MessageBox} This message box
30161 progress : function(title, msg){
30168 minWidth: this.minProgressWidth,
30175 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30176 * If a callback function is passed it will be called after the user clicks the button, and the
30177 * id of the button that was clicked will be passed as the only parameter to the callback
30178 * (could also be the top-right close button).
30179 * @param {String} title The title bar text
30180 * @param {String} msg The message box body text
30181 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30182 * @param {Object} scope (optional) The scope of the callback function
30183 * @return {Roo.MessageBox} This message box
30185 alert : function(title, msg, fn, scope){
30198 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30199 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30200 * You are responsible for closing the message box when the process is complete.
30201 * @param {String} msg The message box body text
30202 * @param {String} title (optional) The title bar text
30203 * @return {Roo.MessageBox} This message box
30205 wait : function(msg, title){
30216 waitTimer = Roo.TaskMgr.start({
30218 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30226 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30227 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30228 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30229 * @param {String} title The title bar text
30230 * @param {String} msg The message box body text
30231 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30232 * @param {Object} scope (optional) The scope of the callback function
30233 * @return {Roo.MessageBox} This message box
30235 confirm : function(title, msg, fn, scope){
30239 buttons: this.YESNO,
30248 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30249 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30250 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30251 * (could also be the top-right close button) and the text that was entered will be passed as the two
30252 * parameters to the callback.
30253 * @param {String} title The title bar text
30254 * @param {String} msg The message box body text
30255 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30256 * @param {Object} scope (optional) The scope of the callback function
30257 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30258 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30259 * @return {Roo.MessageBox} This message box
30261 prompt : function(title, msg, fn, scope, multiline){
30265 buttons: this.OKCANCEL,
30270 multiline: multiline,
30277 * Button config that displays a single OK button
30282 * Button config that displays Yes and No buttons
30285 YESNO : {yes:true, no:true},
30287 * Button config that displays OK and Cancel buttons
30290 OKCANCEL : {ok:true, cancel:true},
30292 * Button config that displays Yes, No and Cancel buttons
30295 YESNOCANCEL : {yes:true, no:true, cancel:true},
30298 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30301 defaultTextHeight : 75,
30303 * The maximum width in pixels of the message box (defaults to 600)
30308 * The minimum width in pixels of the message box (defaults to 100)
30313 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30314 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30317 minProgressWidth : 250,
30319 * An object containing the default button text strings that can be overriden for localized language support.
30320 * Supported properties are: ok, cancel, yes and no.
30321 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30334 * Shorthand for {@link Roo.MessageBox}
30336 Roo.Msg = Roo.MessageBox;/*
30338 * Ext JS Library 1.1.1
30339 * Copyright(c) 2006-2007, Ext JS, LLC.
30341 * Originally Released Under LGPL - original licence link has changed is not relivant.
30344 * <script type="text/javascript">
30347 * @class Roo.QuickTips
30348 * Provides attractive and customizable tooltips for any element.
30351 Roo.QuickTips = function(){
30352 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30353 var ce, bd, xy, dd;
30354 var visible = false, disabled = true, inited = false;
30355 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30357 var onOver = function(e){
30361 var t = e.getTarget();
30362 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30365 if(ce && t == ce.el){
30366 clearTimeout(hideProc);
30369 if(t && tagEls[t.id]){
30370 tagEls[t.id].el = t;
30371 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30374 var ttp, et = Roo.fly(t);
30375 var ns = cfg.namespace;
30376 if(tm.interceptTitles && t.title){
30379 t.removeAttribute("title");
30380 e.preventDefault();
30382 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30385 showProc = show.defer(tm.showDelay, tm, [{
30388 width: et.getAttributeNS(ns, cfg.width),
30389 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30390 title: et.getAttributeNS(ns, cfg.title),
30391 cls: et.getAttributeNS(ns, cfg.cls)
30396 var onOut = function(e){
30397 clearTimeout(showProc);
30398 var t = e.getTarget();
30399 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30400 hideProc = setTimeout(hide, tm.hideDelay);
30404 var onMove = function(e){
30410 if(tm.trackMouse && ce){
30415 var onDown = function(e){
30416 clearTimeout(showProc);
30417 clearTimeout(hideProc);
30419 if(tm.hideOnClick){
30422 tm.enable.defer(100, tm);
30427 var getPad = function(){
30428 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30431 var show = function(o){
30435 clearTimeout(dismissProc);
30437 if(removeCls){ // in case manually hidden
30438 el.removeClass(removeCls);
30442 el.addClass(ce.cls);
30443 removeCls = ce.cls;
30446 tipTitle.update(ce.title);
30449 tipTitle.update('');
30452 el.dom.style.width = tm.maxWidth+'px';
30453 //tipBody.dom.style.width = '';
30454 tipBodyText.update(o.text);
30455 var p = getPad(), w = ce.width;
30457 var td = tipBodyText.dom;
30458 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30459 if(aw > tm.maxWidth){
30461 }else if(aw < tm.minWidth){
30467 //tipBody.setWidth(w);
30468 el.setWidth(parseInt(w, 10) + p);
30469 if(ce.autoHide === false){
30470 close.setDisplayed(true);
30475 close.setDisplayed(false);
30481 el.avoidY = xy[1]-18;
30486 el.setStyle("visibility", "visible");
30487 el.fadeIn({callback: afterShow});
30493 var afterShow = function(){
30497 if(tm.autoDismiss && ce.autoHide !== false){
30498 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30503 var hide = function(noanim){
30504 clearTimeout(dismissProc);
30505 clearTimeout(hideProc);
30507 if(el.isVisible()){
30509 if(noanim !== true && tm.animate){
30510 el.fadeOut({callback: afterHide});
30517 var afterHide = function(){
30520 el.removeClass(removeCls);
30527 * @cfg {Number} minWidth
30528 * The minimum width of the quick tip (defaults to 40)
30532 * @cfg {Number} maxWidth
30533 * The maximum width of the quick tip (defaults to 300)
30537 * @cfg {Boolean} interceptTitles
30538 * True to automatically use the element's DOM title value if available (defaults to false)
30540 interceptTitles : false,
30542 * @cfg {Boolean} trackMouse
30543 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30545 trackMouse : false,
30547 * @cfg {Boolean} hideOnClick
30548 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30550 hideOnClick : true,
30552 * @cfg {Number} showDelay
30553 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30557 * @cfg {Number} hideDelay
30558 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30562 * @cfg {Boolean} autoHide
30563 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30564 * Used in conjunction with hideDelay.
30569 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30570 * (defaults to true). Used in conjunction with autoDismissDelay.
30572 autoDismiss : true,
30575 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30577 autoDismissDelay : 5000,
30579 * @cfg {Boolean} animate
30580 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30585 * @cfg {String} title
30586 * Title text to display (defaults to ''). This can be any valid HTML markup.
30590 * @cfg {String} text
30591 * Body text to display (defaults to ''). This can be any valid HTML markup.
30595 * @cfg {String} cls
30596 * A CSS class to apply to the base quick tip element (defaults to '').
30600 * @cfg {Number} width
30601 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30602 * minWidth or maxWidth.
30607 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30608 * or display QuickTips in a page.
30611 tm = Roo.QuickTips;
30612 cfg = tm.tagConfig;
30614 if(!Roo.isReady){ // allow calling of init() before onReady
30615 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30618 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30619 el.fxDefaults = {stopFx: true};
30620 // maximum custom styling
30621 //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>');
30622 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>');
30623 tipTitle = el.child('h3');
30624 tipTitle.enableDisplayMode("block");
30625 tipBody = el.child('div.x-tip-bd');
30626 tipBodyText = el.child('div.x-tip-bd-inner');
30627 //bdLeft = el.child('div.x-tip-bd-left');
30628 //bdRight = el.child('div.x-tip-bd-right');
30629 close = el.child('div.x-tip-close');
30630 close.enableDisplayMode("block");
30631 close.on("click", hide);
30632 var d = Roo.get(document);
30633 d.on("mousedown", onDown);
30634 d.on("mouseover", onOver);
30635 d.on("mouseout", onOut);
30636 d.on("mousemove", onMove);
30637 esc = d.addKeyListener(27, hide);
30640 dd = el.initDD("default", null, {
30641 onDrag : function(){
30645 dd.setHandleElId(tipTitle.id);
30654 * Configures a new quick tip instance and assigns it to a target element. The following config options
30657 Property Type Description
30658 ---------- --------------------- ------------------------------------------------------------------------
30659 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30661 * @param {Object} config The config object
30663 register : function(config){
30664 var cs = config instanceof Array ? config : arguments;
30665 for(var i = 0, len = cs.length; i < len; i++) {
30667 var target = c.target;
30669 if(target instanceof Array){
30670 for(var j = 0, jlen = target.length; j < jlen; j++){
30671 tagEls[target[j]] = c;
30674 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30681 * Removes this quick tip from its element and destroys it.
30682 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30684 unregister : function(el){
30685 delete tagEls[Roo.id(el)];
30689 * Enable this quick tip.
30691 enable : function(){
30692 if(inited && disabled){
30694 if(locks.length < 1){
30701 * Disable this quick tip.
30703 disable : function(){
30705 clearTimeout(showProc);
30706 clearTimeout(hideProc);
30707 clearTimeout(dismissProc);
30715 * Returns true if the quick tip is enabled, else false.
30717 isEnabled : function(){
30724 attribute : "qtip",
30734 // backwards compat
30735 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30737 * Ext JS Library 1.1.1
30738 * Copyright(c) 2006-2007, Ext JS, LLC.
30740 * Originally Released Under LGPL - original licence link has changed is not relivant.
30743 * <script type="text/javascript">
30748 * @class Roo.tree.TreePanel
30749 * @extends Roo.data.Tree
30751 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30752 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30753 * @cfg {Boolean} enableDD true to enable drag and drop
30754 * @cfg {Boolean} enableDrag true to enable just drag
30755 * @cfg {Boolean} enableDrop true to enable just drop
30756 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30757 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30758 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30759 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30760 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30761 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30762 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30763 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30764 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30765 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30766 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30767 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30768 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30769 * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30770 * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30773 * @param {String/HTMLElement/Element} el The container element
30774 * @param {Object} config
30776 Roo.tree.TreePanel = function(el, config){
30778 var loader = false;
30780 root = config.root;
30781 delete config.root;
30783 if (config.loader) {
30784 loader = config.loader;
30785 delete config.loader;
30788 Roo.apply(this, config);
30789 Roo.tree.TreePanel.superclass.constructor.call(this);
30790 this.el = Roo.get(el);
30791 this.el.addClass('x-tree');
30792 //console.log(root);
30794 this.setRootNode( Roo.factory(root, Roo.tree));
30797 this.loader = Roo.factory(loader, Roo.tree);
30800 * Read-only. The id of the container element becomes this TreePanel's id.
30802 this.id = this.el.id;
30805 * @event beforeload
30806 * Fires before a node is loaded, return false to cancel
30807 * @param {Node} node The node being loaded
30809 "beforeload" : true,
30812 * Fires when a node is loaded
30813 * @param {Node} node The node that was loaded
30817 * @event textchange
30818 * Fires when the text for a node is changed
30819 * @param {Node} node The node
30820 * @param {String} text The new text
30821 * @param {String} oldText The old text
30823 "textchange" : true,
30825 * @event beforeexpand
30826 * Fires before a node is expanded, return false to cancel.
30827 * @param {Node} node The node
30828 * @param {Boolean} deep
30829 * @param {Boolean} anim
30831 "beforeexpand" : true,
30833 * @event beforecollapse
30834 * Fires before a node is collapsed, return false to cancel.
30835 * @param {Node} node The node
30836 * @param {Boolean} deep
30837 * @param {Boolean} anim
30839 "beforecollapse" : true,
30842 * Fires when a node is expanded
30843 * @param {Node} node The node
30847 * @event disabledchange
30848 * Fires when the disabled status of a node changes
30849 * @param {Node} node The node
30850 * @param {Boolean} disabled
30852 "disabledchange" : true,
30855 * Fires when a node is collapsed
30856 * @param {Node} node The node
30860 * @event beforeclick
30861 * Fires before click processing on a node. Return false to cancel the default action.
30862 * @param {Node} node The node
30863 * @param {Roo.EventObject} e The event object
30865 "beforeclick":true,
30867 * @event checkchange
30868 * Fires when a node with a checkbox's checked property changes
30869 * @param {Node} this This node
30870 * @param {Boolean} checked
30872 "checkchange":true,
30875 * Fires when a node is clicked
30876 * @param {Node} node The node
30877 * @param {Roo.EventObject} e The event object
30882 * Fires when a node is double clicked
30883 * @param {Node} node The node
30884 * @param {Roo.EventObject} e The event object
30888 * @event contextmenu
30889 * Fires when a node is right clicked
30890 * @param {Node} node The node
30891 * @param {Roo.EventObject} e The event object
30893 "contextmenu":true,
30895 * @event beforechildrenrendered
30896 * Fires right before the child nodes for a node are rendered
30897 * @param {Node} node The node
30899 "beforechildrenrendered":true,
30902 * Fires when a node starts being dragged
30903 * @param {Roo.tree.TreePanel} this
30904 * @param {Roo.tree.TreeNode} node
30905 * @param {event} e The raw browser event
30907 "startdrag" : true,
30910 * Fires when a drag operation is complete
30911 * @param {Roo.tree.TreePanel} this
30912 * @param {Roo.tree.TreeNode} node
30913 * @param {event} e The raw browser event
30918 * Fires when a dragged node is dropped on a valid DD target
30919 * @param {Roo.tree.TreePanel} this
30920 * @param {Roo.tree.TreeNode} node
30921 * @param {DD} dd The dd it was dropped on
30922 * @param {event} e The raw browser event
30926 * @event beforenodedrop
30927 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30928 * passed to handlers has the following properties:<br />
30929 * <ul style="padding:5px;padding-left:16px;">
30930 * <li>tree - The TreePanel</li>
30931 * <li>target - The node being targeted for the drop</li>
30932 * <li>data - The drag data from the drag source</li>
30933 * <li>point - The point of the drop - append, above or below</li>
30934 * <li>source - The drag source</li>
30935 * <li>rawEvent - Raw mouse event</li>
30936 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30937 * to be inserted by setting them on this object.</li>
30938 * <li>cancel - Set this to true to cancel the drop.</li>
30940 * @param {Object} dropEvent
30942 "beforenodedrop" : true,
30945 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30946 * passed to handlers has the following properties:<br />
30947 * <ul style="padding:5px;padding-left:16px;">
30948 * <li>tree - The TreePanel</li>
30949 * <li>target - The node being targeted for the drop</li>
30950 * <li>data - The drag data from the drag source</li>
30951 * <li>point - The point of the drop - append, above or below</li>
30952 * <li>source - The drag source</li>
30953 * <li>rawEvent - Raw mouse event</li>
30954 * <li>dropNode - Dropped node(s).</li>
30956 * @param {Object} dropEvent
30960 * @event nodedragover
30961 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30962 * passed to handlers has the following properties:<br />
30963 * <ul style="padding:5px;padding-left:16px;">
30964 * <li>tree - The TreePanel</li>
30965 * <li>target - The node being targeted for the drop</li>
30966 * <li>data - The drag data from the drag source</li>
30967 * <li>point - The point of the drop - append, above or below</li>
30968 * <li>source - The drag source</li>
30969 * <li>rawEvent - Raw mouse event</li>
30970 * <li>dropNode - Drop node(s) provided by the source.</li>
30971 * <li>cancel - Set this to true to signal drop not allowed.</li>
30973 * @param {Object} dragOverEvent
30975 "nodedragover" : true
30978 if(this.singleExpand){
30979 this.on("beforeexpand", this.restrictExpand, this);
30982 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30983 rootVisible : true,
30984 animate: Roo.enableFx,
30987 hlDrop : Roo.enableFx,
30991 rendererTip: false,
30993 restrictExpand : function(node){
30994 var p = node.parentNode;
30996 if(p.expandedChild && p.expandedChild.parentNode == p){
30997 p.expandedChild.collapse();
30999 p.expandedChild = node;
31003 // private override
31004 setRootNode : function(node){
31005 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31006 if(!this.rootVisible){
31007 node.ui = new Roo.tree.RootTreeNodeUI(node);
31013 * Returns the container element for this TreePanel
31015 getEl : function(){
31020 * Returns the default TreeLoader for this TreePanel
31022 getLoader : function(){
31023 return this.loader;
31029 expandAll : function(){
31030 this.root.expand(true);
31034 * Collapse all nodes
31036 collapseAll : function(){
31037 this.root.collapse(true);
31041 * Returns the selection model used by this TreePanel
31043 getSelectionModel : function(){
31044 if(!this.selModel){
31045 this.selModel = new Roo.tree.DefaultSelectionModel();
31047 return this.selModel;
31051 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31052 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31053 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31056 getChecked : function(a, startNode){
31057 startNode = startNode || this.root;
31059 var f = function(){
31060 if(this.attributes.checked){
31061 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31064 startNode.cascade(f);
31069 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31070 * @param {String} path
31071 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31072 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31073 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31075 expandPath : function(path, attr, callback){
31076 attr = attr || "id";
31077 var keys = path.split(this.pathSeparator);
31078 var curNode = this.root;
31079 if(curNode.attributes[attr] != keys[1]){ // invalid root
31081 callback(false, null);
31086 var f = function(){
31087 if(++index == keys.length){
31089 callback(true, curNode);
31093 var c = curNode.findChild(attr, keys[index]);
31096 callback(false, curNode);
31101 c.expand(false, false, f);
31103 curNode.expand(false, false, f);
31107 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31108 * @param {String} path
31109 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31110 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31111 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31113 selectPath : function(path, attr, callback){
31114 attr = attr || "id";
31115 var keys = path.split(this.pathSeparator);
31116 var v = keys.pop();
31117 if(keys.length > 0){
31118 var f = function(success, node){
31119 if(success && node){
31120 var n = node.findChild(attr, v);
31126 }else if(callback){
31127 callback(false, n);
31131 callback(false, n);
31135 this.expandPath(keys.join(this.pathSeparator), attr, f);
31137 this.root.select();
31139 callback(true, this.root);
31144 getTreeEl : function(){
31149 * Trigger rendering of this TreePanel
31151 render : function(){
31152 if (this.innerCt) {
31153 return this; // stop it rendering more than once!!
31156 this.innerCt = this.el.createChild({tag:"ul",
31157 cls:"x-tree-root-ct " +
31158 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31160 if(this.containerScroll){
31161 Roo.dd.ScrollManager.register(this.el);
31163 if((this.enableDD || this.enableDrop) && !this.dropZone){
31165 * The dropZone used by this tree if drop is enabled
31166 * @type Roo.tree.TreeDropZone
31168 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31169 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31172 if((this.enableDD || this.enableDrag) && !this.dragZone){
31174 * The dragZone used by this tree if drag is enabled
31175 * @type Roo.tree.TreeDragZone
31177 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31178 ddGroup: this.ddGroup || "TreeDD",
31179 scroll: this.ddScroll
31182 this.getSelectionModel().init(this);
31184 console.log("ROOT not set in tree");
31187 this.root.render();
31188 if(!this.rootVisible){
31189 this.root.renderChildren();
31195 * Ext JS Library 1.1.1
31196 * Copyright(c) 2006-2007, Ext JS, LLC.
31198 * Originally Released Under LGPL - original licence link has changed is not relivant.
31201 * <script type="text/javascript">
31206 * @class Roo.tree.DefaultSelectionModel
31207 * @extends Roo.util.Observable
31208 * The default single selection for a TreePanel.
31210 Roo.tree.DefaultSelectionModel = function(){
31211 this.selNode = null;
31215 * @event selectionchange
31216 * Fires when the selected node changes
31217 * @param {DefaultSelectionModel} this
31218 * @param {TreeNode} node the new selection
31220 "selectionchange" : true,
31223 * @event beforeselect
31224 * Fires before the selected node changes, return false to cancel the change
31225 * @param {DefaultSelectionModel} this
31226 * @param {TreeNode} node the new selection
31227 * @param {TreeNode} node the old selection
31229 "beforeselect" : true
31233 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31234 init : function(tree){
31236 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31237 tree.on("click", this.onNodeClick, this);
31240 onNodeClick : function(node, e){
31241 if (e.ctrlKey && this.selNode == node) {
31242 this.unselect(node);
31250 * @param {TreeNode} node The node to select
31251 * @return {TreeNode} The selected node
31253 select : function(node){
31254 var last = this.selNode;
31255 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31257 last.ui.onSelectedChange(false);
31259 this.selNode = node;
31260 node.ui.onSelectedChange(true);
31261 this.fireEvent("selectionchange", this, node, last);
31268 * @param {TreeNode} node The node to unselect
31270 unselect : function(node){
31271 if(this.selNode == node){
31272 this.clearSelections();
31277 * Clear all selections
31279 clearSelections : function(){
31280 var n = this.selNode;
31282 n.ui.onSelectedChange(false);
31283 this.selNode = null;
31284 this.fireEvent("selectionchange", this, null);
31290 * Get the selected node
31291 * @return {TreeNode} The selected node
31293 getSelectedNode : function(){
31294 return this.selNode;
31298 * Returns true if the node is selected
31299 * @param {TreeNode} node The node to check
31300 * @return {Boolean}
31302 isSelected : function(node){
31303 return this.selNode == node;
31307 * Selects the node above the selected node in the tree, intelligently walking the nodes
31308 * @return TreeNode The new selection
31310 selectPrevious : function(){
31311 var s = this.selNode || this.lastSelNode;
31315 var ps = s.previousSibling;
31317 if(!ps.isExpanded() || ps.childNodes.length < 1){
31318 return this.select(ps);
31320 var lc = ps.lastChild;
31321 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31324 return this.select(lc);
31326 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31327 return this.select(s.parentNode);
31333 * Selects the node above the selected node in the tree, intelligently walking the nodes
31334 * @return TreeNode The new selection
31336 selectNext : function(){
31337 var s = this.selNode || this.lastSelNode;
31341 if(s.firstChild && s.isExpanded()){
31342 return this.select(s.firstChild);
31343 }else if(s.nextSibling){
31344 return this.select(s.nextSibling);
31345 }else if(s.parentNode){
31347 s.parentNode.bubble(function(){
31348 if(this.nextSibling){
31349 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31358 onKeyDown : function(e){
31359 var s = this.selNode || this.lastSelNode;
31360 // undesirable, but required
31365 var k = e.getKey();
31373 this.selectPrevious();
31376 e.preventDefault();
31377 if(s.hasChildNodes()){
31378 if(!s.isExpanded()){
31380 }else if(s.firstChild){
31381 this.select(s.firstChild, e);
31386 e.preventDefault();
31387 if(s.hasChildNodes() && s.isExpanded()){
31389 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31390 this.select(s.parentNode, e);
31398 * @class Roo.tree.MultiSelectionModel
31399 * @extends Roo.util.Observable
31400 * Multi selection for a TreePanel.
31402 Roo.tree.MultiSelectionModel = function(){
31403 this.selNodes = [];
31407 * @event selectionchange
31408 * Fires when the selected nodes change
31409 * @param {MultiSelectionModel} this
31410 * @param {Array} nodes Array of the selected nodes
31412 "selectionchange" : true
31416 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31417 init : function(tree){
31419 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31420 tree.on("click", this.onNodeClick, this);
31423 onNodeClick : function(node, e){
31424 this.select(node, e, e.ctrlKey);
31429 * @param {TreeNode} node The node to select
31430 * @param {EventObject} e (optional) An event associated with the selection
31431 * @param {Boolean} keepExisting True to retain existing selections
31432 * @return {TreeNode} The selected node
31434 select : function(node, e, keepExisting){
31435 if(keepExisting !== true){
31436 this.clearSelections(true);
31438 if(this.isSelected(node)){
31439 this.lastSelNode = node;
31442 this.selNodes.push(node);
31443 this.selMap[node.id] = node;
31444 this.lastSelNode = node;
31445 node.ui.onSelectedChange(true);
31446 this.fireEvent("selectionchange", this, this.selNodes);
31452 * @param {TreeNode} node The node to unselect
31454 unselect : function(node){
31455 if(this.selMap[node.id]){
31456 node.ui.onSelectedChange(false);
31457 var sn = this.selNodes;
31460 index = sn.indexOf(node);
31462 for(var i = 0, len = sn.length; i < len; i++){
31470 this.selNodes.splice(index, 1);
31472 delete this.selMap[node.id];
31473 this.fireEvent("selectionchange", this, this.selNodes);
31478 * Clear all selections
31480 clearSelections : function(suppressEvent){
31481 var sn = this.selNodes;
31483 for(var i = 0, len = sn.length; i < len; i++){
31484 sn[i].ui.onSelectedChange(false);
31486 this.selNodes = [];
31488 if(suppressEvent !== true){
31489 this.fireEvent("selectionchange", this, this.selNodes);
31495 * Returns true if the node is selected
31496 * @param {TreeNode} node The node to check
31497 * @return {Boolean}
31499 isSelected : function(node){
31500 return this.selMap[node.id] ? true : false;
31504 * Returns an array of the selected nodes
31507 getSelectedNodes : function(){
31508 return this.selNodes;
31511 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31513 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31515 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31518 * Ext JS Library 1.1.1
31519 * Copyright(c) 2006-2007, Ext JS, LLC.
31521 * Originally Released Under LGPL - original licence link has changed is not relivant.
31524 * <script type="text/javascript">
31528 * @class Roo.tree.TreeNode
31529 * @extends Roo.data.Node
31530 * @cfg {String} text The text for this node
31531 * @cfg {Boolean} expanded true to start the node expanded
31532 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31533 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31534 * @cfg {Boolean} disabled true to start the node disabled
31535 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31536 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31537 * @cfg {String} cls A css class to be added to the node
31538 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31539 * @cfg {String} href URL of the link used for the node (defaults to #)
31540 * @cfg {String} hrefTarget target frame for the link
31541 * @cfg {String} qtip An Ext QuickTip for the node
31542 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31543 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31544 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31545 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31546 * (defaults to undefined with no checkbox rendered)
31548 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31550 Roo.tree.TreeNode = function(attributes){
31551 attributes = attributes || {};
31552 if(typeof attributes == "string"){
31553 attributes = {text: attributes};
31555 this.childrenRendered = false;
31556 this.rendered = false;
31557 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31558 this.expanded = attributes.expanded === true;
31559 this.isTarget = attributes.isTarget !== false;
31560 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31561 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31564 * Read-only. The text for this node. To change it use setText().
31567 this.text = attributes.text;
31569 * True if this node is disabled.
31572 this.disabled = attributes.disabled === true;
31576 * @event textchange
31577 * Fires when the text for this node is changed
31578 * @param {Node} this This node
31579 * @param {String} text The new text
31580 * @param {String} oldText The old text
31582 "textchange" : true,
31584 * @event beforeexpand
31585 * Fires before this node is expanded, return false to cancel.
31586 * @param {Node} this This node
31587 * @param {Boolean} deep
31588 * @param {Boolean} anim
31590 "beforeexpand" : true,
31592 * @event beforecollapse
31593 * Fires before this node is collapsed, return false to cancel.
31594 * @param {Node} this This node
31595 * @param {Boolean} deep
31596 * @param {Boolean} anim
31598 "beforecollapse" : true,
31601 * Fires when this node is expanded
31602 * @param {Node} this This node
31606 * @event disabledchange
31607 * Fires when the disabled status of this node changes
31608 * @param {Node} this This node
31609 * @param {Boolean} disabled
31611 "disabledchange" : true,
31614 * Fires when this node is collapsed
31615 * @param {Node} this This node
31619 * @event beforeclick
31620 * Fires before click processing. Return false to cancel the default action.
31621 * @param {Node} this This node
31622 * @param {Roo.EventObject} e The event object
31624 "beforeclick":true,
31626 * @event checkchange
31627 * Fires when a node with a checkbox's checked property changes
31628 * @param {Node} this This node
31629 * @param {Boolean} checked
31631 "checkchange":true,
31634 * Fires when this node is clicked
31635 * @param {Node} this This node
31636 * @param {Roo.EventObject} e The event object
31641 * Fires when this node is double clicked
31642 * @param {Node} this This node
31643 * @param {Roo.EventObject} e The event object
31647 * @event contextmenu
31648 * Fires when this node is right clicked
31649 * @param {Node} this This node
31650 * @param {Roo.EventObject} e The event object
31652 "contextmenu":true,
31654 * @event beforechildrenrendered
31655 * Fires right before the child nodes for this node are rendered
31656 * @param {Node} this This node
31658 "beforechildrenrendered":true
31661 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31664 * Read-only. The UI for this node
31667 this.ui = new uiClass(this);
31669 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31670 preventHScroll: true,
31672 * Returns true if this node is expanded
31673 * @return {Boolean}
31675 isExpanded : function(){
31676 return this.expanded;
31680 * Returns the UI object for this node
31681 * @return {TreeNodeUI}
31683 getUI : function(){
31687 // private override
31688 setFirstChild : function(node){
31689 var of = this.firstChild;
31690 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31691 if(this.childrenRendered && of && node != of){
31692 of.renderIndent(true, true);
31695 this.renderIndent(true, true);
31699 // private override
31700 setLastChild : function(node){
31701 var ol = this.lastChild;
31702 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31703 if(this.childrenRendered && ol && node != ol){
31704 ol.renderIndent(true, true);
31707 this.renderIndent(true, true);
31711 // these methods are overridden to provide lazy rendering support
31712 // private override
31713 appendChild : function(){
31714 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31715 if(node && this.childrenRendered){
31718 this.ui.updateExpandIcon();
31722 // private override
31723 removeChild : function(node){
31724 this.ownerTree.getSelectionModel().unselect(node);
31725 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31726 // if it's been rendered remove dom node
31727 if(this.childrenRendered){
31730 if(this.childNodes.length < 1){
31731 this.collapse(false, false);
31733 this.ui.updateExpandIcon();
31735 if(!this.firstChild) {
31736 this.childrenRendered = false;
31741 // private override
31742 insertBefore : function(node, refNode){
31743 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31744 if(newNode && refNode && this.childrenRendered){
31747 this.ui.updateExpandIcon();
31752 * Sets the text for this node
31753 * @param {String} text
31755 setText : function(text){
31756 var oldText = this.text;
31758 this.attributes.text = text;
31759 if(this.rendered){ // event without subscribing
31760 this.ui.onTextChange(this, text, oldText);
31762 this.fireEvent("textchange", this, text, oldText);
31766 * Triggers selection of this node
31768 select : function(){
31769 this.getOwnerTree().getSelectionModel().select(this);
31773 * Triggers deselection of this node
31775 unselect : function(){
31776 this.getOwnerTree().getSelectionModel().unselect(this);
31780 * Returns true if this node is selected
31781 * @return {Boolean}
31783 isSelected : function(){
31784 return this.getOwnerTree().getSelectionModel().isSelected(this);
31788 * Expand this node.
31789 * @param {Boolean} deep (optional) True to expand all children as well
31790 * @param {Boolean} anim (optional) false to cancel the default animation
31791 * @param {Function} callback (optional) A callback to be called when
31792 * expanding this node completes (does not wait for deep expand to complete).
31793 * Called with 1 parameter, this node.
31795 expand : function(deep, anim, callback){
31796 if(!this.expanded){
31797 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31800 if(!this.childrenRendered){
31801 this.renderChildren();
31803 this.expanded = true;
31804 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31805 this.ui.animExpand(function(){
31806 this.fireEvent("expand", this);
31807 if(typeof callback == "function"){
31811 this.expandChildNodes(true);
31813 }.createDelegate(this));
31817 this.fireEvent("expand", this);
31818 if(typeof callback == "function"){
31823 if(typeof callback == "function"){
31828 this.expandChildNodes(true);
31832 isHiddenRoot : function(){
31833 return this.isRoot && !this.getOwnerTree().rootVisible;
31837 * Collapse this node.
31838 * @param {Boolean} deep (optional) True to collapse all children as well
31839 * @param {Boolean} anim (optional) false to cancel the default animation
31841 collapse : function(deep, anim){
31842 if(this.expanded && !this.isHiddenRoot()){
31843 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31846 this.expanded = false;
31847 if((this.getOwnerTree().animate && anim !== false) || anim){
31848 this.ui.animCollapse(function(){
31849 this.fireEvent("collapse", this);
31851 this.collapseChildNodes(true);
31853 }.createDelegate(this));
31856 this.ui.collapse();
31857 this.fireEvent("collapse", this);
31861 var cs = this.childNodes;
31862 for(var i = 0, len = cs.length; i < len; i++) {
31863 cs[i].collapse(true, false);
31869 delayedExpand : function(delay){
31870 if(!this.expandProcId){
31871 this.expandProcId = this.expand.defer(delay, this);
31876 cancelExpand : function(){
31877 if(this.expandProcId){
31878 clearTimeout(this.expandProcId);
31880 this.expandProcId = false;
31884 * Toggles expanded/collapsed state of the node
31886 toggle : function(){
31895 * Ensures all parent nodes are expanded
31897 ensureVisible : function(callback){
31898 var tree = this.getOwnerTree();
31899 tree.expandPath(this.parentNode.getPath(), false, function(){
31900 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31901 Roo.callback(callback);
31902 }.createDelegate(this));
31906 * Expand all child nodes
31907 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31909 expandChildNodes : function(deep){
31910 var cs = this.childNodes;
31911 for(var i = 0, len = cs.length; i < len; i++) {
31912 cs[i].expand(deep);
31917 * Collapse all child nodes
31918 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31920 collapseChildNodes : function(deep){
31921 var cs = this.childNodes;
31922 for(var i = 0, len = cs.length; i < len; i++) {
31923 cs[i].collapse(deep);
31928 * Disables this node
31930 disable : function(){
31931 this.disabled = true;
31933 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31934 this.ui.onDisableChange(this, true);
31936 this.fireEvent("disabledchange", this, true);
31940 * Enables this node
31942 enable : function(){
31943 this.disabled = false;
31944 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31945 this.ui.onDisableChange(this, false);
31947 this.fireEvent("disabledchange", this, false);
31951 renderChildren : function(suppressEvent){
31952 if(suppressEvent !== false){
31953 this.fireEvent("beforechildrenrendered", this);
31955 var cs = this.childNodes;
31956 for(var i = 0, len = cs.length; i < len; i++){
31957 cs[i].render(true);
31959 this.childrenRendered = true;
31963 sort : function(fn, scope){
31964 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31965 if(this.childrenRendered){
31966 var cs = this.childNodes;
31967 for(var i = 0, len = cs.length; i < len; i++){
31968 cs[i].render(true);
31974 render : function(bulkRender){
31975 this.ui.render(bulkRender);
31976 if(!this.rendered){
31977 this.rendered = true;
31979 this.expanded = false;
31980 this.expand(false, false);
31986 renderIndent : function(deep, refresh){
31988 this.ui.childIndent = null;
31990 this.ui.renderIndent();
31991 if(deep === true && this.childrenRendered){
31992 var cs = this.childNodes;
31993 for(var i = 0, len = cs.length; i < len; i++){
31994 cs[i].renderIndent(true, refresh);
32000 * Ext JS Library 1.1.1
32001 * Copyright(c) 2006-2007, Ext JS, LLC.
32003 * Originally Released Under LGPL - original licence link has changed is not relivant.
32006 * <script type="text/javascript">
32010 * @class Roo.tree.AsyncTreeNode
32011 * @extends Roo.tree.TreeNode
32012 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32014 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32016 Roo.tree.AsyncTreeNode = function(config){
32017 this.loaded = false;
32018 this.loading = false;
32019 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32021 * @event beforeload
32022 * Fires before this node is loaded, return false to cancel
32023 * @param {Node} this This node
32025 this.addEvents({'beforeload':true, 'load': true});
32028 * Fires when this node is loaded
32029 * @param {Node} this This node
32032 * The loader used by this node (defaults to using the tree's defined loader)
32037 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32038 expand : function(deep, anim, callback){
32039 if(this.loading){ // if an async load is already running, waiting til it's done
32041 var f = function(){
32042 if(!this.loading){ // done loading
32043 clearInterval(timer);
32044 this.expand(deep, anim, callback);
32046 }.createDelegate(this);
32047 timer = setInterval(f, 200);
32051 if(this.fireEvent("beforeload", this) === false){
32054 this.loading = true;
32055 this.ui.beforeLoad(this);
32056 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32058 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32062 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32066 * Returns true if this node is currently loading
32067 * @return {Boolean}
32069 isLoading : function(){
32070 return this.loading;
32073 loadComplete : function(deep, anim, callback){
32074 this.loading = false;
32075 this.loaded = true;
32076 this.ui.afterLoad(this);
32077 this.fireEvent("load", this);
32078 this.expand(deep, anim, callback);
32082 * Returns true if this node has been loaded
32083 * @return {Boolean}
32085 isLoaded : function(){
32086 return this.loaded;
32089 hasChildNodes : function(){
32090 if(!this.isLeaf() && !this.loaded){
32093 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32098 * Trigger a reload for this node
32099 * @param {Function} callback
32101 reload : function(callback){
32102 this.collapse(false, false);
32103 while(this.firstChild){
32104 this.removeChild(this.firstChild);
32106 this.childrenRendered = false;
32107 this.loaded = false;
32108 if(this.isHiddenRoot()){
32109 this.expanded = false;
32111 this.expand(false, false, callback);
32115 * Ext JS Library 1.1.1
32116 * Copyright(c) 2006-2007, Ext JS, LLC.
32118 * Originally Released Under LGPL - original licence link has changed is not relivant.
32121 * <script type="text/javascript">
32125 * @class Roo.tree.TreeNodeUI
32127 * @param {Object} node The node to render
32128 * The TreeNode UI implementation is separate from the
32129 * tree implementation. Unless you are customizing the tree UI,
32130 * you should never have to use this directly.
32132 Roo.tree.TreeNodeUI = function(node){
32134 this.rendered = false;
32135 this.animating = false;
32136 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32139 Roo.tree.TreeNodeUI.prototype = {
32140 removeChild : function(node){
32142 this.ctNode.removeChild(node.ui.getEl());
32146 beforeLoad : function(){
32147 this.addClass("x-tree-node-loading");
32150 afterLoad : function(){
32151 this.removeClass("x-tree-node-loading");
32154 onTextChange : function(node, text, oldText){
32156 this.textNode.innerHTML = text;
32160 onDisableChange : function(node, state){
32161 this.disabled = state;
32163 this.addClass("x-tree-node-disabled");
32165 this.removeClass("x-tree-node-disabled");
32169 onSelectedChange : function(state){
32172 this.addClass("x-tree-selected");
32175 this.removeClass("x-tree-selected");
32179 onMove : function(tree, node, oldParent, newParent, index, refNode){
32180 this.childIndent = null;
32182 var targetNode = newParent.ui.getContainer();
32183 if(!targetNode){//target not rendered
32184 this.holder = document.createElement("div");
32185 this.holder.appendChild(this.wrap);
32188 var insertBefore = refNode ? refNode.ui.getEl() : null;
32190 targetNode.insertBefore(this.wrap, insertBefore);
32192 targetNode.appendChild(this.wrap);
32194 this.node.renderIndent(true);
32198 addClass : function(cls){
32200 Roo.fly(this.elNode).addClass(cls);
32204 removeClass : function(cls){
32206 Roo.fly(this.elNode).removeClass(cls);
32210 remove : function(){
32212 this.holder = document.createElement("div");
32213 this.holder.appendChild(this.wrap);
32217 fireEvent : function(){
32218 return this.node.fireEvent.apply(this.node, arguments);
32221 initEvents : function(){
32222 this.node.on("move", this.onMove, this);
32223 var E = Roo.EventManager;
32224 var a = this.anchor;
32226 var el = Roo.fly(a, '_treeui');
32228 if(Roo.isOpera){ // opera render bug ignores the CSS
32229 el.setStyle("text-decoration", "none");
32232 el.on("click", this.onClick, this);
32233 el.on("dblclick", this.onDblClick, this);
32236 Roo.EventManager.on(this.checkbox,
32237 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32240 el.on("contextmenu", this.onContextMenu, this);
32242 var icon = Roo.fly(this.iconNode);
32243 icon.on("click", this.onClick, this);
32244 icon.on("dblclick", this.onDblClick, this);
32245 icon.on("contextmenu", this.onContextMenu, this);
32246 E.on(this.ecNode, "click", this.ecClick, this, true);
32248 if(this.node.disabled){
32249 this.addClass("x-tree-node-disabled");
32251 if(this.node.hidden){
32252 this.addClass("x-tree-node-disabled");
32254 var ot = this.node.getOwnerTree();
32255 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32256 if(dd && (!this.node.isRoot || ot.rootVisible)){
32257 Roo.dd.Registry.register(this.elNode, {
32259 handles: this.getDDHandles(),
32265 getDDHandles : function(){
32266 return [this.iconNode, this.textNode];
32271 this.wrap.style.display = "none";
32277 this.wrap.style.display = "";
32281 onContextMenu : function(e){
32282 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32283 e.preventDefault();
32285 this.fireEvent("contextmenu", this.node, e);
32289 onClick : function(e){
32294 if(this.fireEvent("beforeclick", this.node, e) !== false){
32295 if(!this.disabled && this.node.attributes.href){
32296 this.fireEvent("click", this.node, e);
32299 e.preventDefault();
32304 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32305 this.node.toggle();
32308 this.fireEvent("click", this.node, e);
32314 onDblClick : function(e){
32315 e.preventDefault();
32320 this.toggleCheck();
32322 if(!this.animating && this.node.hasChildNodes()){
32323 this.node.toggle();
32325 this.fireEvent("dblclick", this.node, e);
32328 onCheckChange : function(){
32329 var checked = this.checkbox.checked;
32330 this.node.attributes.checked = checked;
32331 this.fireEvent('checkchange', this.node, checked);
32334 ecClick : function(e){
32335 if(!this.animating && this.node.hasChildNodes()){
32336 this.node.toggle();
32340 startDrop : function(){
32341 this.dropping = true;
32344 // delayed drop so the click event doesn't get fired on a drop
32345 endDrop : function(){
32346 setTimeout(function(){
32347 this.dropping = false;
32348 }.createDelegate(this), 50);
32351 expand : function(){
32352 this.updateExpandIcon();
32353 this.ctNode.style.display = "";
32356 focus : function(){
32357 if(!this.node.preventHScroll){
32358 try{this.anchor.focus();
32360 }else if(!Roo.isIE){
32362 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32363 var l = noscroll.scrollLeft;
32364 this.anchor.focus();
32365 noscroll.scrollLeft = l;
32370 toggleCheck : function(value){
32371 var cb = this.checkbox;
32373 cb.checked = (value === undefined ? !cb.checked : value);
32379 this.anchor.blur();
32383 animExpand : function(callback){
32384 var ct = Roo.get(this.ctNode);
32386 if(!this.node.hasChildNodes()){
32387 this.updateExpandIcon();
32388 this.ctNode.style.display = "";
32389 Roo.callback(callback);
32392 this.animating = true;
32393 this.updateExpandIcon();
32396 callback : function(){
32397 this.animating = false;
32398 Roo.callback(callback);
32401 duration: this.node.ownerTree.duration || .25
32405 highlight : function(){
32406 var tree = this.node.getOwnerTree();
32407 Roo.fly(this.wrap).highlight(
32408 tree.hlColor || "C3DAF9",
32409 {endColor: tree.hlBaseColor}
32413 collapse : function(){
32414 this.updateExpandIcon();
32415 this.ctNode.style.display = "none";
32418 animCollapse : function(callback){
32419 var ct = Roo.get(this.ctNode);
32420 ct.enableDisplayMode('block');
32423 this.animating = true;
32424 this.updateExpandIcon();
32427 callback : function(){
32428 this.animating = false;
32429 Roo.callback(callback);
32432 duration: this.node.ownerTree.duration || .25
32436 getContainer : function(){
32437 return this.ctNode;
32440 getEl : function(){
32444 appendDDGhost : function(ghostNode){
32445 ghostNode.appendChild(this.elNode.cloneNode(true));
32448 getDDRepairXY : function(){
32449 return Roo.lib.Dom.getXY(this.iconNode);
32452 onRender : function(){
32456 render : function(bulkRender){
32457 var n = this.node, a = n.attributes;
32458 var targetNode = n.parentNode ?
32459 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32461 if(!this.rendered){
32462 this.rendered = true;
32464 this.renderElements(n, a, targetNode, bulkRender);
32467 if(this.textNode.setAttributeNS){
32468 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32470 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32473 this.textNode.setAttribute("ext:qtip", a.qtip);
32475 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32478 }else if(a.qtipCfg){
32479 a.qtipCfg.target = Roo.id(this.textNode);
32480 Roo.QuickTips.register(a.qtipCfg);
32483 if(!this.node.expanded){
32484 this.updateExpandIcon();
32487 if(bulkRender === true) {
32488 targetNode.appendChild(this.wrap);
32493 renderElements : function(n, a, targetNode, bulkRender){
32494 // add some indent caching, this helps performance when rendering a large tree
32495 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32496 var t = n.getOwnerTree();
32497 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32498 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32499 var cb = typeof a.checked == 'boolean';
32500 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32501 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32502 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32503 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32504 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32505 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32506 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32507 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32508 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32509 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32512 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32513 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32514 n.nextSibling.ui.getEl(), buf.join(""));
32516 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32519 this.elNode = this.wrap.childNodes[0];
32520 this.ctNode = this.wrap.childNodes[1];
32521 var cs = this.elNode.childNodes;
32522 this.indentNode = cs[0];
32523 this.ecNode = cs[1];
32524 this.iconNode = cs[2];
32527 this.checkbox = cs[3];
32530 this.anchor = cs[index];
32531 this.textNode = cs[index].firstChild;
32534 getAnchor : function(){
32535 return this.anchor;
32538 getTextEl : function(){
32539 return this.textNode;
32542 getIconEl : function(){
32543 return this.iconNode;
32546 isChecked : function(){
32547 return this.checkbox ? this.checkbox.checked : false;
32550 updateExpandIcon : function(){
32552 var n = this.node, c1, c2;
32553 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32554 var hasChild = n.hasChildNodes();
32558 c1 = "x-tree-node-collapsed";
32559 c2 = "x-tree-node-expanded";
32562 c1 = "x-tree-node-expanded";
32563 c2 = "x-tree-node-collapsed";
32566 this.removeClass("x-tree-node-leaf");
32567 this.wasLeaf = false;
32569 if(this.c1 != c1 || this.c2 != c2){
32570 Roo.fly(this.elNode).replaceClass(c1, c2);
32571 this.c1 = c1; this.c2 = c2;
32575 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32578 this.wasLeaf = true;
32581 var ecc = "x-tree-ec-icon "+cls;
32582 if(this.ecc != ecc){
32583 this.ecNode.className = ecc;
32589 getChildIndent : function(){
32590 if(!this.childIndent){
32594 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32596 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32598 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32603 this.childIndent = buf.join("");
32605 return this.childIndent;
32608 renderIndent : function(){
32611 var p = this.node.parentNode;
32613 indent = p.ui.getChildIndent();
32615 if(this.indentMarkup != indent){ // don't rerender if not required
32616 this.indentNode.innerHTML = indent;
32617 this.indentMarkup = indent;
32619 this.updateExpandIcon();
32624 Roo.tree.RootTreeNodeUI = function(){
32625 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32627 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32628 render : function(){
32629 if(!this.rendered){
32630 var targetNode = this.node.ownerTree.innerCt.dom;
32631 this.node.expanded = true;
32632 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32633 this.wrap = this.ctNode = targetNode.firstChild;
32636 collapse : function(){
32638 expand : function(){
32642 * Ext JS Library 1.1.1
32643 * Copyright(c) 2006-2007, Ext JS, LLC.
32645 * Originally Released Under LGPL - original licence link has changed is not relivant.
32648 * <script type="text/javascript">
32651 * @class Roo.tree.TreeLoader
32652 * @extends Roo.util.Observable
32653 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32654 * nodes from a specified URL. The response must be a javascript Array definition
32655 * who's elements are node definition objects. eg:
32657 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32658 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32661 * A server request is sent, and child nodes are loaded only when a node is expanded.
32662 * The loading node's id is passed to the server under the parameter name "node" to
32663 * enable the server to produce the correct child nodes.
32665 * To pass extra parameters, an event handler may be attached to the "beforeload"
32666 * event, and the parameters specified in the TreeLoader's baseParams property:
32668 myTreeLoader.on("beforeload", function(treeLoader, node) {
32669 this.baseParams.category = node.attributes.category;
32672 * This would pass an HTTP parameter called "category" to the server containing
32673 * the value of the Node's "category" attribute.
32675 * Creates a new Treeloader.
32676 * @param {Object} config A config object containing config properties.
32678 Roo.tree.TreeLoader = function(config){
32679 this.baseParams = {};
32680 this.requestMethod = "POST";
32681 Roo.apply(this, config);
32686 * @event beforeload
32687 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32688 * @param {Object} This TreeLoader object.
32689 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32690 * @param {Object} callback The callback function specified in the {@link #load} call.
32695 * Fires when the node has been successfuly loaded.
32696 * @param {Object} This TreeLoader object.
32697 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32698 * @param {Object} response The response object containing the data from the server.
32702 * @event loadexception
32703 * Fires if the network request failed.
32704 * @param {Object} This TreeLoader object.
32705 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32706 * @param {Object} response The response object containing the data from the server.
32708 loadexception : true,
32711 * Fires before a node is created, enabling you to return custom Node types
32712 * @param {Object} This TreeLoader object.
32713 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32718 Roo.tree.TreeLoader.superclass.constructor.call(this);
32721 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32723 * @cfg {String} dataUrl The URL from which to request a Json string which
32724 * specifies an array of node definition object representing the child nodes
32728 * @cfg {Object} baseParams (optional) An object containing properties which
32729 * specify HTTP parameters to be passed to each request for child nodes.
32732 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32733 * created by this loader. If the attributes sent by the server have an attribute in this object,
32734 * they take priority.
32737 * @cfg {Object} uiProviders (optional) An object containing properties which
32739 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32740 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32741 * <i>uiProvider</i> attribute of a returned child node is a string rather
32742 * than a reference to a TreeNodeUI implementation, this that string value
32743 * is used as a property name in the uiProviders object. You can define the provider named
32744 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32749 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32750 * child nodes before loading.
32752 clearOnLoad : true,
32755 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32756 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32757 * Grid query { data : [ .....] }
32762 * @cfg {String} queryParam (optional)
32763 * Name of the query as it will be passed on the querystring (defaults to 'node')
32764 * eg. the request will be ?node=[id]
32771 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32772 * This is called automatically when a node is expanded, but may be used to reload
32773 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32774 * @param {Roo.tree.TreeNode} node
32775 * @param {Function} callback
32777 load : function(node, callback){
32778 if(this.clearOnLoad){
32779 while(node.firstChild){
32780 node.removeChild(node.firstChild);
32783 if(node.attributes.children){ // preloaded json children
32784 var cs = node.attributes.children;
32785 for(var i = 0, len = cs.length; i < len; i++){
32786 node.appendChild(this.createNode(cs[i]));
32788 if(typeof callback == "function"){
32791 }else if(this.dataUrl){
32792 this.requestData(node, callback);
32796 getParams: function(node){
32797 var buf = [], bp = this.baseParams;
32798 for(var key in bp){
32799 if(typeof bp[key] != "function"){
32800 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32803 var n = this.queryParam === false ? 'node' : this.queryParam;
32804 buf.push(n + "=", encodeURIComponent(node.id));
32805 return buf.join("");
32808 requestData : function(node, callback){
32809 if(this.fireEvent("beforeload", this, node, callback) !== false){
32810 this.transId = Roo.Ajax.request({
32811 method:this.requestMethod,
32812 url: this.dataUrl||this.url,
32813 success: this.handleResponse,
32814 failure: this.handleFailure,
32816 argument: {callback: callback, node: node},
32817 params: this.getParams(node)
32820 // if the load is cancelled, make sure we notify
32821 // the node that we are done
32822 if(typeof callback == "function"){
32828 isLoading : function(){
32829 return this.transId ? true : false;
32832 abort : function(){
32833 if(this.isLoading()){
32834 Roo.Ajax.abort(this.transId);
32839 createNode : function(attr){
32840 // apply baseAttrs, nice idea Corey!
32841 if(this.baseAttrs){
32842 Roo.applyIf(attr, this.baseAttrs);
32844 if(this.applyLoader !== false){
32845 attr.loader = this;
32847 // uiProvider = depreciated..
32849 if(typeof(attr.uiProvider) == 'string'){
32850 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32851 /** eval:var:attr */ eval(attr.uiProvider);
32853 if(typeof(this.uiProviders['default']) != 'undefined') {
32854 attr.uiProvider = this.uiProviders['default'];
32857 this.fireEvent('create', this, attr);
32859 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32861 new Roo.tree.TreeNode(attr) :
32862 new Roo.tree.AsyncTreeNode(attr));
32865 processResponse : function(response, node, callback){
32866 var json = response.responseText;
32869 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32870 if (this.root !== false) {
32874 for(var i = 0, len = o.length; i < len; i++){
32875 var n = this.createNode(o[i]);
32877 node.appendChild(n);
32880 if(typeof callback == "function"){
32881 callback(this, node);
32884 this.handleFailure(response);
32888 handleResponse : function(response){
32889 this.transId = false;
32890 var a = response.argument;
32891 this.processResponse(response, a.node, a.callback);
32892 this.fireEvent("load", this, a.node, response);
32895 handleFailure : function(response){
32896 this.transId = false;
32897 var a = response.argument;
32898 this.fireEvent("loadexception", this, a.node, response);
32899 if(typeof a.callback == "function"){
32900 a.callback(this, a.node);
32905 * Ext JS Library 1.1.1
32906 * Copyright(c) 2006-2007, Ext JS, LLC.
32908 * Originally Released Under LGPL - original licence link has changed is not relivant.
32911 * <script type="text/javascript">
32915 * @class Roo.tree.TreeFilter
32916 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32917 * @param {TreePanel} tree
32918 * @param {Object} config (optional)
32920 Roo.tree.TreeFilter = function(tree, config){
32922 this.filtered = {};
32923 Roo.apply(this, config);
32926 Roo.tree.TreeFilter.prototype = {
32933 * Filter the data by a specific attribute.
32934 * @param {String/RegExp} value Either string that the attribute value
32935 * should start with or a RegExp to test against the attribute
32936 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32937 * @param {TreeNode} startNode (optional) The node to start the filter at.
32939 filter : function(value, attr, startNode){
32940 attr = attr || "text";
32942 if(typeof value == "string"){
32943 var vlen = value.length;
32944 // auto clear empty filter
32945 if(vlen == 0 && this.clearBlank){
32949 value = value.toLowerCase();
32951 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32953 }else if(value.exec){ // regex?
32955 return value.test(n.attributes[attr]);
32958 throw 'Illegal filter type, must be string or regex';
32960 this.filterBy(f, null, startNode);
32964 * Filter by a function. The passed function will be called with each
32965 * node in the tree (or from the startNode). If the function returns true, the node is kept
32966 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32967 * @param {Function} fn The filter function
32968 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32970 filterBy : function(fn, scope, startNode){
32971 startNode = startNode || this.tree.root;
32972 if(this.autoClear){
32975 var af = this.filtered, rv = this.reverse;
32976 var f = function(n){
32977 if(n == startNode){
32983 var m = fn.call(scope || n, n);
32991 startNode.cascade(f);
32994 if(typeof id != "function"){
32996 if(n && n.parentNode){
32997 n.parentNode.removeChild(n);
33005 * Clears the current filter. Note: with the "remove" option
33006 * set a filter cannot be cleared.
33008 clear : function(){
33010 var af = this.filtered;
33012 if(typeof id != "function"){
33019 this.filtered = {};
33024 * Ext JS Library 1.1.1
33025 * Copyright(c) 2006-2007, Ext JS, LLC.
33027 * Originally Released Under LGPL - original licence link has changed is not relivant.
33030 * <script type="text/javascript">
33035 * @class Roo.tree.TreeSorter
33036 * Provides sorting of nodes in a TreePanel
33038 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33039 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33040 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33041 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33042 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33043 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33045 * @param {TreePanel} tree
33046 * @param {Object} config
33048 Roo.tree.TreeSorter = function(tree, config){
33049 Roo.apply(this, config);
33050 tree.on("beforechildrenrendered", this.doSort, this);
33051 tree.on("append", this.updateSort, this);
33052 tree.on("insert", this.updateSort, this);
33054 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33055 var p = this.property || "text";
33056 var sortType = this.sortType;
33057 var fs = this.folderSort;
33058 var cs = this.caseSensitive === true;
33059 var leafAttr = this.leafAttr || 'leaf';
33061 this.sortFn = function(n1, n2){
33063 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33066 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33070 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33071 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33073 return dsc ? +1 : -1;
33075 return dsc ? -1 : +1;
33082 Roo.tree.TreeSorter.prototype = {
33083 doSort : function(node){
33084 node.sort(this.sortFn);
33087 compareNodes : function(n1, n2){
33088 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33091 updateSort : function(tree, node){
33092 if(node.childrenRendered){
33093 this.doSort.defer(1, this, [node]);
33098 * Ext JS Library 1.1.1
33099 * Copyright(c) 2006-2007, Ext JS, LLC.
33101 * Originally Released Under LGPL - original licence link has changed is not relivant.
33104 * <script type="text/javascript">
33107 if(Roo.dd.DropZone){
33109 Roo.tree.TreeDropZone = function(tree, config){
33110 this.allowParentInsert = false;
33111 this.allowContainerDrop = false;
33112 this.appendOnly = false;
33113 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33115 this.lastInsertClass = "x-tree-no-status";
33116 this.dragOverData = {};
33119 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33120 ddGroup : "TreeDD",
33122 expandDelay : 1000,
33124 expandNode : function(node){
33125 if(node.hasChildNodes() && !node.isExpanded()){
33126 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33130 queueExpand : function(node){
33131 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33134 cancelExpand : function(){
33135 if(this.expandProcId){
33136 clearTimeout(this.expandProcId);
33137 this.expandProcId = false;
33141 isValidDropPoint : function(n, pt, dd, e, data){
33142 if(!n || !data){ return false; }
33143 var targetNode = n.node;
33144 var dropNode = data.node;
33145 // default drop rules
33146 if(!(targetNode && targetNode.isTarget && pt)){
33149 if(pt == "append" && targetNode.allowChildren === false){
33152 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33155 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33158 // reuse the object
33159 var overEvent = this.dragOverData;
33160 overEvent.tree = this.tree;
33161 overEvent.target = targetNode;
33162 overEvent.data = data;
33163 overEvent.point = pt;
33164 overEvent.source = dd;
33165 overEvent.rawEvent = e;
33166 overEvent.dropNode = dropNode;
33167 overEvent.cancel = false;
33168 var result = this.tree.fireEvent("nodedragover", overEvent);
33169 return overEvent.cancel === false && result !== false;
33172 getDropPoint : function(e, n, dd){
33175 return tn.allowChildren !== false ? "append" : false; // always append for root
33177 var dragEl = n.ddel;
33178 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33179 var y = Roo.lib.Event.getPageY(e);
33180 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33182 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33183 var noAppend = tn.allowChildren === false;
33184 if(this.appendOnly || tn.parentNode.allowChildren === false){
33185 return noAppend ? false : "append";
33187 var noBelow = false;
33188 if(!this.allowParentInsert){
33189 noBelow = tn.hasChildNodes() && tn.isExpanded();
33191 var q = (b - t) / (noAppend ? 2 : 3);
33192 if(y >= t && y < (t + q)){
33194 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33201 onNodeEnter : function(n, dd, e, data){
33202 this.cancelExpand();
33205 onNodeOver : function(n, dd, e, data){
33206 var pt = this.getDropPoint(e, n, dd);
33209 // auto node expand check
33210 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33211 this.queueExpand(node);
33212 }else if(pt != "append"){
33213 this.cancelExpand();
33216 // set the insert point style on the target node
33217 var returnCls = this.dropNotAllowed;
33218 if(this.isValidDropPoint(n, pt, dd, e, data)){
33223 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33224 cls = "x-tree-drag-insert-above";
33225 }else if(pt == "below"){
33226 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33227 cls = "x-tree-drag-insert-below";
33229 returnCls = "x-tree-drop-ok-append";
33230 cls = "x-tree-drag-append";
33232 if(this.lastInsertClass != cls){
33233 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33234 this.lastInsertClass = cls;
33241 onNodeOut : function(n, dd, e, data){
33242 this.cancelExpand();
33243 this.removeDropIndicators(n);
33246 onNodeDrop : function(n, dd, e, data){
33247 var point = this.getDropPoint(e, n, dd);
33248 var targetNode = n.node;
33249 targetNode.ui.startDrop();
33250 if(!this.isValidDropPoint(n, point, dd, e, data)){
33251 targetNode.ui.endDrop();
33254 // first try to find the drop node
33255 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33258 target: targetNode,
33263 dropNode: dropNode,
33266 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33267 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33268 targetNode.ui.endDrop();
33271 // allow target changing
33272 targetNode = dropEvent.target;
33273 if(point == "append" && !targetNode.isExpanded()){
33274 targetNode.expand(false, null, function(){
33275 this.completeDrop(dropEvent);
33276 }.createDelegate(this));
33278 this.completeDrop(dropEvent);
33283 completeDrop : function(de){
33284 var ns = de.dropNode, p = de.point, t = de.target;
33285 if(!(ns instanceof Array)){
33289 for(var i = 0, len = ns.length; i < len; i++){
33292 t.parentNode.insertBefore(n, t);
33293 }else if(p == "below"){
33294 t.parentNode.insertBefore(n, t.nextSibling);
33300 if(this.tree.hlDrop){
33304 this.tree.fireEvent("nodedrop", de);
33307 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33308 if(this.tree.hlDrop){
33309 dropNode.ui.focus();
33310 dropNode.ui.highlight();
33312 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33315 getTree : function(){
33319 removeDropIndicators : function(n){
33322 Roo.fly(el).removeClass([
33323 "x-tree-drag-insert-above",
33324 "x-tree-drag-insert-below",
33325 "x-tree-drag-append"]);
33326 this.lastInsertClass = "_noclass";
33330 beforeDragDrop : function(target, e, id){
33331 this.cancelExpand();
33335 afterRepair : function(data){
33336 if(data && Roo.enableFx){
33337 data.node.ui.highlight();
33346 * Ext JS Library 1.1.1
33347 * Copyright(c) 2006-2007, Ext JS, LLC.
33349 * Originally Released Under LGPL - original licence link has changed is not relivant.
33352 * <script type="text/javascript">
33356 if(Roo.dd.DragZone){
33357 Roo.tree.TreeDragZone = function(tree, config){
33358 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33362 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33363 ddGroup : "TreeDD",
33365 onBeforeDrag : function(data, e){
33367 return n && n.draggable && !n.disabled;
33370 onInitDrag : function(e){
33371 var data = this.dragData;
33372 this.tree.getSelectionModel().select(data.node);
33373 this.proxy.update("");
33374 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33375 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33378 getRepairXY : function(e, data){
33379 return data.node.ui.getDDRepairXY();
33382 onEndDrag : function(data, e){
33383 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33386 onValidDrop : function(dd, e, id){
33387 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33391 beforeInvalidDrop : function(e, id){
33392 // this scrolls the original position back into view
33393 var sm = this.tree.getSelectionModel();
33394 sm.clearSelections();
33395 sm.select(this.dragData.node);
33400 * Ext JS Library 1.1.1
33401 * Copyright(c) 2006-2007, Ext JS, LLC.
33403 * Originally Released Under LGPL - original licence link has changed is not relivant.
33406 * <script type="text/javascript">
33409 * @class Roo.tree.TreeEditor
33410 * @extends Roo.Editor
33411 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33412 * as the editor field.
33414 * @param {TreePanel} tree
33415 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33417 Roo.tree.TreeEditor = function(tree, config){
33418 config = config || {};
33419 var field = config.events ? config : new Roo.form.TextField(config);
33420 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33424 tree.on('beforeclick', this.beforeNodeClick, this);
33425 tree.getTreeEl().on('mousedown', this.hide, this);
33426 this.on('complete', this.updateNode, this);
33427 this.on('beforestartedit', this.fitToTree, this);
33428 this.on('startedit', this.bindScroll, this, {delay:10});
33429 this.on('specialkey', this.onSpecialKey, this);
33432 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33434 * @cfg {String} alignment
33435 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33441 * @cfg {Boolean} hideEl
33442 * True to hide the bound element while the editor is displayed (defaults to false)
33446 * @cfg {String} cls
33447 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33449 cls: "x-small-editor x-tree-editor",
33451 * @cfg {Boolean} shim
33452 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33458 * @cfg {Number} maxWidth
33459 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33460 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33461 * scroll and client offsets into account prior to each edit.
33468 fitToTree : function(ed, el){
33469 var td = this.tree.getTreeEl().dom, nd = el.dom;
33470 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33471 td.scrollLeft = nd.offsetLeft;
33475 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33476 this.setSize(w, '');
33480 triggerEdit : function(node){
33481 this.completeEdit();
33482 this.editNode = node;
33483 this.startEdit(node.ui.textNode, node.text);
33487 bindScroll : function(){
33488 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33492 beforeNodeClick : function(node, e){
33493 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33494 this.lastClick = new Date();
33495 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33497 this.triggerEdit(node);
33503 updateNode : function(ed, value){
33504 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33505 this.editNode.setText(value);
33509 onHide : function(){
33510 Roo.tree.TreeEditor.superclass.onHide.call(this);
33512 this.editNode.ui.focus();
33517 onSpecialKey : function(field, e){
33518 var k = e.getKey();
33522 }else if(k == e.ENTER && !e.hasModifier()){
33524 this.completeEdit();
33527 });//<Script type="text/javascript">
33530 * Ext JS Library 1.1.1
33531 * Copyright(c) 2006-2007, Ext JS, LLC.
33533 * Originally Released Under LGPL - original licence link has changed is not relivant.
33536 * <script type="text/javascript">
33540 * Not documented??? - probably should be...
33543 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33544 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33546 renderElements : function(n, a, targetNode, bulkRender){
33547 //consel.log("renderElements?");
33548 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33550 var t = n.getOwnerTree();
33551 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33553 var cols = t.columns;
33554 var bw = t.borderWidth;
33556 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33557 var cb = typeof a.checked == "boolean";
33558 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33559 var colcls = 'x-t-' + tid + '-c0';
33561 '<li class="x-tree-node">',
33564 '<div class="x-tree-node-el ', a.cls,'">',
33566 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33569 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33570 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33571 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33572 (a.icon ? ' x-tree-node-inline-icon' : ''),
33573 (a.iconCls ? ' '+a.iconCls : ''),
33574 '" unselectable="on" />',
33575 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33576 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33578 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33579 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33580 '<span unselectable="on" qtip="' + tx + '">',
33584 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33585 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33587 for(var i = 1, len = cols.length; i < len; i++){
33589 colcls = 'x-t-' + tid + '-c' +i;
33590 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33591 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33592 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33598 '<div class="x-clear"></div></div>',
33599 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33602 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33603 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33604 n.nextSibling.ui.getEl(), buf.join(""));
33606 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33608 var el = this.wrap.firstChild;
33610 this.elNode = el.firstChild;
33611 this.ranchor = el.childNodes[1];
33612 this.ctNode = this.wrap.childNodes[1];
33613 var cs = el.firstChild.childNodes;
33614 this.indentNode = cs[0];
33615 this.ecNode = cs[1];
33616 this.iconNode = cs[2];
33619 this.checkbox = cs[3];
33622 this.anchor = cs[index];
33624 this.textNode = cs[index].firstChild;
33626 //el.on("click", this.onClick, this);
33627 //el.on("dblclick", this.onDblClick, this);
33630 // console.log(this);
33632 initEvents : function(){
33633 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33636 var a = this.ranchor;
33638 var el = Roo.get(a);
33640 if(Roo.isOpera){ // opera render bug ignores the CSS
33641 el.setStyle("text-decoration", "none");
33644 el.on("click", this.onClick, this);
33645 el.on("dblclick", this.onDblClick, this);
33646 el.on("contextmenu", this.onContextMenu, this);
33650 /*onSelectedChange : function(state){
33653 this.addClass("x-tree-selected");
33656 this.removeClass("x-tree-selected");
33659 addClass : function(cls){
33661 Roo.fly(this.elRow).addClass(cls);
33667 removeClass : function(cls){
33669 Roo.fly(this.elRow).removeClass(cls);
33675 });//<Script type="text/javascript">
33679 * Ext JS Library 1.1.1
33680 * Copyright(c) 2006-2007, Ext JS, LLC.
33682 * Originally Released Under LGPL - original licence link has changed is not relivant.
33685 * <script type="text/javascript">
33690 * @class Roo.tree.ColumnTree
33691 * @extends Roo.data.TreePanel
33692 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33693 * @cfg {int} borderWidth compined right/left border allowance
33695 * @param {String/HTMLElement/Element} el The container element
33696 * @param {Object} config
33698 Roo.tree.ColumnTree = function(el, config)
33700 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33704 * Fire this event on a container when it resizes
33705 * @param {int} w Width
33706 * @param {int} h Height
33710 this.on('resize', this.onResize, this);
33713 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33717 borderWidth: Roo.isBorderBox ? 0 : 2,
33720 render : function(){
33721 // add the header.....
33723 Roo.tree.ColumnTree.superclass.render.apply(this);
33725 this.el.addClass('x-column-tree');
33727 this.headers = this.el.createChild(
33728 {cls:'x-tree-headers'},this.innerCt.dom);
33730 var cols = this.columns, c;
33731 var totalWidth = 0;
33733 var len = cols.length;
33734 for(var i = 0; i < len; i++){
33736 totalWidth += c.width;
33737 this.headEls.push(this.headers.createChild({
33738 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33740 cls:'x-tree-hd-text',
33743 style:'width:'+(c.width-this.borderWidth)+'px;'
33746 this.headers.createChild({cls:'x-clear'});
33747 // prevent floats from wrapping when clipped
33748 this.headers.setWidth(totalWidth);
33749 //this.innerCt.setWidth(totalWidth);
33750 this.innerCt.setStyle({ overflow: 'auto' });
33751 this.onResize(this.width, this.height);
33755 onResize : function(w,h)
33760 this.innerCt.setWidth(this.width);
33761 this.innerCt.setHeight(this.height-20);
33764 var cols = this.columns, c;
33765 var totalWidth = 0;
33767 var len = cols.length;
33768 for(var i = 0; i < len; i++){
33770 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33771 // it's the expander..
33772 expEl = this.headEls[i];
33775 totalWidth += c.width;
33779 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33781 this.headers.setWidth(w-20);
33790 * Ext JS Library 1.1.1
33791 * Copyright(c) 2006-2007, Ext JS, LLC.
33793 * Originally Released Under LGPL - original licence link has changed is not relivant.
33796 * <script type="text/javascript">
33800 * @class Roo.menu.Menu
33801 * @extends Roo.util.Observable
33802 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33803 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33805 * Creates a new Menu
33806 * @param {Object} config Configuration options
33808 Roo.menu.Menu = function(config){
33809 Roo.apply(this, config);
33810 this.id = this.id || Roo.id();
33813 * @event beforeshow
33814 * Fires before this menu is displayed
33815 * @param {Roo.menu.Menu} this
33819 * @event beforehide
33820 * Fires before this menu is hidden
33821 * @param {Roo.menu.Menu} this
33826 * Fires after this menu is displayed
33827 * @param {Roo.menu.Menu} this
33832 * Fires after this menu is hidden
33833 * @param {Roo.menu.Menu} this
33838 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33839 * @param {Roo.menu.Menu} this
33840 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33841 * @param {Roo.EventObject} e
33846 * Fires when the mouse is hovering over this menu
33847 * @param {Roo.menu.Menu} this
33848 * @param {Roo.EventObject} e
33849 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33854 * Fires when the mouse exits this menu
33855 * @param {Roo.menu.Menu} this
33856 * @param {Roo.EventObject} e
33857 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33862 * Fires when a menu item contained in this menu is clicked
33863 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33864 * @param {Roo.EventObject} e
33868 if (this.registerMenu) {
33869 Roo.menu.MenuMgr.register(this);
33872 var mis = this.items;
33873 this.items = new Roo.util.MixedCollection();
33875 this.add.apply(this, mis);
33879 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33881 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33885 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33886 * for bottom-right shadow (defaults to "sides")
33890 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33891 * this menu (defaults to "tl-tr?")
33893 subMenuAlign : "tl-tr?",
33895 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33896 * relative to its element of origin (defaults to "tl-bl?")
33898 defaultAlign : "tl-bl?",
33900 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33902 allowOtherMenus : false,
33904 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33906 registerMenu : true,
33911 render : function(){
33915 var el = this.el = new Roo.Layer({
33917 shadow:this.shadow,
33919 parentEl: this.parentEl || document.body,
33923 this.keyNav = new Roo.menu.MenuNav(this);
33926 el.addClass("x-menu-plain");
33929 el.addClass(this.cls);
33931 // generic focus element
33932 this.focusEl = el.createChild({
33933 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33935 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33936 ul.on("click", this.onClick, this);
33937 ul.on("mouseover", this.onMouseOver, this);
33938 ul.on("mouseout", this.onMouseOut, this);
33939 this.items.each(function(item){
33940 var li = document.createElement("li");
33941 li.className = "x-menu-list-item";
33942 ul.dom.appendChild(li);
33943 item.render(li, this);
33950 autoWidth : function(){
33951 var el = this.el, ul = this.ul;
33955 var w = this.width;
33958 }else if(Roo.isIE){
33959 el.setWidth(this.minWidth);
33960 var t = el.dom.offsetWidth; // force recalc
33961 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33966 delayAutoWidth : function(){
33969 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33971 this.awTask.delay(20);
33976 findTargetItem : function(e){
33977 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33978 if(t && t.menuItemId){
33979 return this.items.get(t.menuItemId);
33984 onClick : function(e){
33986 if(t = this.findTargetItem(e)){
33988 this.fireEvent("click", this, t, e);
33993 setActiveItem : function(item, autoExpand){
33994 if(item != this.activeItem){
33995 if(this.activeItem){
33996 this.activeItem.deactivate();
33998 this.activeItem = item;
33999 item.activate(autoExpand);
34000 }else if(autoExpand){
34006 tryActivate : function(start, step){
34007 var items = this.items;
34008 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34009 var item = items.get(i);
34010 if(!item.disabled && item.canActivate){
34011 this.setActiveItem(item, false);
34019 onMouseOver : function(e){
34021 if(t = this.findTargetItem(e)){
34022 if(t.canActivate && !t.disabled){
34023 this.setActiveItem(t, true);
34026 this.fireEvent("mouseover", this, e, t);
34030 onMouseOut : function(e){
34032 if(t = this.findTargetItem(e)){
34033 if(t == this.activeItem && t.shouldDeactivate(e)){
34034 this.activeItem.deactivate();
34035 delete this.activeItem;
34038 this.fireEvent("mouseout", this, e, t);
34042 * Read-only. Returns true if the menu is currently displayed, else false.
34045 isVisible : function(){
34046 return this.el && !this.hidden;
34050 * Displays this menu relative to another element
34051 * @param {String/HTMLElement/Roo.Element} element The element to align to
34052 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34053 * the element (defaults to this.defaultAlign)
34054 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34056 show : function(el, pos, parentMenu){
34057 this.parentMenu = parentMenu;
34061 this.fireEvent("beforeshow", this);
34062 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34066 * Displays this menu at a specific xy position
34067 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34068 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34070 showAt : function(xy, parentMenu, /* private: */_e){
34071 this.parentMenu = parentMenu;
34076 this.fireEvent("beforeshow", this);
34077 xy = this.el.adjustForConstraints(xy);
34081 this.hidden = false;
34083 this.fireEvent("show", this);
34086 focus : function(){
34088 this.doFocus.defer(50, this);
34092 doFocus : function(){
34094 this.focusEl.focus();
34099 * Hides this menu and optionally all parent menus
34100 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34102 hide : function(deep){
34103 if(this.el && this.isVisible()){
34104 this.fireEvent("beforehide", this);
34105 if(this.activeItem){
34106 this.activeItem.deactivate();
34107 this.activeItem = null;
34110 this.hidden = true;
34111 this.fireEvent("hide", this);
34113 if(deep === true && this.parentMenu){
34114 this.parentMenu.hide(true);
34119 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34120 * Any of the following are valid:
34122 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34123 * <li>An HTMLElement object which will be converted to a menu item</li>
34124 * <li>A menu item config object that will be created as a new menu item</li>
34125 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34126 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34131 var menu = new Roo.menu.Menu();
34133 // Create a menu item to add by reference
34134 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34136 // Add a bunch of items at once using different methods.
34137 // Only the last item added will be returned.
34138 var item = menu.add(
34139 menuItem, // add existing item by ref
34140 'Dynamic Item', // new TextItem
34141 '-', // new separator
34142 { text: 'Config Item' } // new item by config
34145 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34146 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34149 var a = arguments, l = a.length, item;
34150 for(var i = 0; i < l; i++){
34152 if ((typeof(el) == "object") && el.xtype && el.xns) {
34153 el = Roo.factory(el, Roo.menu);
34156 if(el.render){ // some kind of Item
34157 item = this.addItem(el);
34158 }else if(typeof el == "string"){ // string
34159 if(el == "separator" || el == "-"){
34160 item = this.addSeparator();
34162 item = this.addText(el);
34164 }else if(el.tagName || el.el){ // element
34165 item = this.addElement(el);
34166 }else if(typeof el == "object"){ // must be menu item config?
34167 item = this.addMenuItem(el);
34174 * Returns this menu's underlying {@link Roo.Element} object
34175 * @return {Roo.Element} The element
34177 getEl : function(){
34185 * Adds a separator bar to the menu
34186 * @return {Roo.menu.Item} The menu item that was added
34188 addSeparator : function(){
34189 return this.addItem(new Roo.menu.Separator());
34193 * Adds an {@link Roo.Element} object to the menu
34194 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34195 * @return {Roo.menu.Item} The menu item that was added
34197 addElement : function(el){
34198 return this.addItem(new Roo.menu.BaseItem(el));
34202 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34203 * @param {Roo.menu.Item} item The menu item to add
34204 * @return {Roo.menu.Item} The menu item that was added
34206 addItem : function(item){
34207 this.items.add(item);
34209 var li = document.createElement("li");
34210 li.className = "x-menu-list-item";
34211 this.ul.dom.appendChild(li);
34212 item.render(li, this);
34213 this.delayAutoWidth();
34219 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34220 * @param {Object} config A MenuItem config object
34221 * @return {Roo.menu.Item} The menu item that was added
34223 addMenuItem : function(config){
34224 if(!(config instanceof Roo.menu.Item)){
34225 if(typeof config.checked == "boolean"){ // must be check menu item config?
34226 config = new Roo.menu.CheckItem(config);
34228 config = new Roo.menu.Item(config);
34231 return this.addItem(config);
34235 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34236 * @param {String} text The text to display in the menu item
34237 * @return {Roo.menu.Item} The menu item that was added
34239 addText : function(text){
34240 return this.addItem(new Roo.menu.TextItem({ text : text }));
34244 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34245 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34246 * @param {Roo.menu.Item} item The menu item to add
34247 * @return {Roo.menu.Item} The menu item that was added
34249 insert : function(index, item){
34250 this.items.insert(index, item);
34252 var li = document.createElement("li");
34253 li.className = "x-menu-list-item";
34254 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34255 item.render(li, this);
34256 this.delayAutoWidth();
34262 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34263 * @param {Roo.menu.Item} item The menu item to remove
34265 remove : function(item){
34266 this.items.removeKey(item.id);
34271 * Removes and destroys all items in the menu
34273 removeAll : function(){
34275 while(f = this.items.first()){
34281 // MenuNav is a private utility class used internally by the Menu
34282 Roo.menu.MenuNav = function(menu){
34283 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34284 this.scope = this.menu = menu;
34287 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34288 doRelay : function(e, h){
34289 var k = e.getKey();
34290 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34291 this.menu.tryActivate(0, 1);
34294 return h.call(this.scope || this, e, this.menu);
34297 up : function(e, m){
34298 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34299 m.tryActivate(m.items.length-1, -1);
34303 down : function(e, m){
34304 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34305 m.tryActivate(0, 1);
34309 right : function(e, m){
34311 m.activeItem.expandMenu(true);
34315 left : function(e, m){
34317 if(m.parentMenu && m.parentMenu.activeItem){
34318 m.parentMenu.activeItem.activate();
34322 enter : function(e, m){
34324 e.stopPropagation();
34325 m.activeItem.onClick(e);
34326 m.fireEvent("click", this, m.activeItem);
34332 * Ext JS Library 1.1.1
34333 * Copyright(c) 2006-2007, Ext JS, LLC.
34335 * Originally Released Under LGPL - original licence link has changed is not relivant.
34338 * <script type="text/javascript">
34342 * @class Roo.menu.MenuMgr
34343 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34346 Roo.menu.MenuMgr = function(){
34347 var menus, active, groups = {}, attached = false, lastShow = new Date();
34349 // private - called when first menu is created
34352 active = new Roo.util.MixedCollection();
34353 Roo.get(document).addKeyListener(27, function(){
34354 if(active.length > 0){
34361 function hideAll(){
34362 if(active && active.length > 0){
34363 var c = active.clone();
34364 c.each(function(m){
34371 function onHide(m){
34373 if(active.length < 1){
34374 Roo.get(document).un("mousedown", onMouseDown);
34380 function onShow(m){
34381 var last = active.last();
34382 lastShow = new Date();
34385 Roo.get(document).on("mousedown", onMouseDown);
34389 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34390 m.parentMenu.activeChild = m;
34391 }else if(last && last.isVisible()){
34392 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34397 function onBeforeHide(m){
34399 m.activeChild.hide();
34401 if(m.autoHideTimer){
34402 clearTimeout(m.autoHideTimer);
34403 delete m.autoHideTimer;
34408 function onBeforeShow(m){
34409 var pm = m.parentMenu;
34410 if(!pm && !m.allowOtherMenus){
34412 }else if(pm && pm.activeChild && active != m){
34413 pm.activeChild.hide();
34418 function onMouseDown(e){
34419 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34425 function onBeforeCheck(mi, state){
34427 var g = groups[mi.group];
34428 for(var i = 0, l = g.length; i < l; i++){
34430 g[i].setChecked(false);
34439 * Hides all menus that are currently visible
34441 hideAll : function(){
34446 register : function(menu){
34450 menus[menu.id] = menu;
34451 menu.on("beforehide", onBeforeHide);
34452 menu.on("hide", onHide);
34453 menu.on("beforeshow", onBeforeShow);
34454 menu.on("show", onShow);
34455 var g = menu.group;
34456 if(g && menu.events["checkchange"]){
34460 groups[g].push(menu);
34461 menu.on("checkchange", onCheck);
34466 * Returns a {@link Roo.menu.Menu} object
34467 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34468 * be used to generate and return a new Menu instance.
34470 get : function(menu){
34471 if(typeof menu == "string"){ // menu id
34472 return menus[menu];
34473 }else if(menu.events){ // menu instance
34475 }else if(typeof menu.length == 'number'){ // array of menu items?
34476 return new Roo.menu.Menu({items:menu});
34477 }else{ // otherwise, must be a config
34478 return new Roo.menu.Menu(menu);
34483 unregister : function(menu){
34484 delete menus[menu.id];
34485 menu.un("beforehide", onBeforeHide);
34486 menu.un("hide", onHide);
34487 menu.un("beforeshow", onBeforeShow);
34488 menu.un("show", onShow);
34489 var g = menu.group;
34490 if(g && menu.events["checkchange"]){
34491 groups[g].remove(menu);
34492 menu.un("checkchange", onCheck);
34497 registerCheckable : function(menuItem){
34498 var g = menuItem.group;
34503 groups[g].push(menuItem);
34504 menuItem.on("beforecheckchange", onBeforeCheck);
34509 unregisterCheckable : function(menuItem){
34510 var g = menuItem.group;
34512 groups[g].remove(menuItem);
34513 menuItem.un("beforecheckchange", onBeforeCheck);
34519 * Ext JS Library 1.1.1
34520 * Copyright(c) 2006-2007, Ext JS, LLC.
34522 * Originally Released Under LGPL - original licence link has changed is not relivant.
34525 * <script type="text/javascript">
34530 * @class Roo.menu.BaseItem
34531 * @extends Roo.Component
34532 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34533 * management and base configuration options shared by all menu components.
34535 * Creates a new BaseItem
34536 * @param {Object} config Configuration options
34538 Roo.menu.BaseItem = function(config){
34539 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34544 * Fires when this item is clicked
34545 * @param {Roo.menu.BaseItem} this
34546 * @param {Roo.EventObject} e
34551 * Fires when this item is activated
34552 * @param {Roo.menu.BaseItem} this
34556 * @event deactivate
34557 * Fires when this item is deactivated
34558 * @param {Roo.menu.BaseItem} this
34564 this.on("click", this.handler, this.scope, true);
34568 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34570 * @cfg {Function} handler
34571 * A function that will handle the click event of this menu item (defaults to undefined)
34574 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34576 canActivate : false,
34578 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34580 activeClass : "x-menu-item-active",
34582 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34584 hideOnClick : true,
34586 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34591 ctype: "Roo.menu.BaseItem",
34594 actionMode : "container",
34597 render : function(container, parentMenu){
34598 this.parentMenu = parentMenu;
34599 Roo.menu.BaseItem.superclass.render.call(this, container);
34600 this.container.menuItemId = this.id;
34604 onRender : function(container, position){
34605 this.el = Roo.get(this.el);
34606 container.dom.appendChild(this.el.dom);
34610 onClick : function(e){
34611 if(!this.disabled && this.fireEvent("click", this, e) !== false
34612 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34613 this.handleClick(e);
34620 activate : function(){
34624 var li = this.container;
34625 li.addClass(this.activeClass);
34626 this.region = li.getRegion().adjust(2, 2, -2, -2);
34627 this.fireEvent("activate", this);
34632 deactivate : function(){
34633 this.container.removeClass(this.activeClass);
34634 this.fireEvent("deactivate", this);
34638 shouldDeactivate : function(e){
34639 return !this.region || !this.region.contains(e.getPoint());
34643 handleClick : function(e){
34644 if(this.hideOnClick){
34645 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34650 expandMenu : function(autoActivate){
34655 hideMenu : function(){
34660 * Ext JS Library 1.1.1
34661 * Copyright(c) 2006-2007, Ext JS, LLC.
34663 * Originally Released Under LGPL - original licence link has changed is not relivant.
34666 * <script type="text/javascript">
34670 * @class Roo.menu.Adapter
34671 * @extends Roo.menu.BaseItem
34672 * 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.
34673 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34675 * Creates a new Adapter
34676 * @param {Object} config Configuration options
34678 Roo.menu.Adapter = function(component, config){
34679 Roo.menu.Adapter.superclass.constructor.call(this, config);
34680 this.component = component;
34682 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34684 canActivate : true,
34687 onRender : function(container, position){
34688 this.component.render(container);
34689 this.el = this.component.getEl();
34693 activate : function(){
34697 this.component.focus();
34698 this.fireEvent("activate", this);
34703 deactivate : function(){
34704 this.fireEvent("deactivate", this);
34708 disable : function(){
34709 this.component.disable();
34710 Roo.menu.Adapter.superclass.disable.call(this);
34714 enable : function(){
34715 this.component.enable();
34716 Roo.menu.Adapter.superclass.enable.call(this);
34720 * Ext JS Library 1.1.1
34721 * Copyright(c) 2006-2007, Ext JS, LLC.
34723 * Originally Released Under LGPL - original licence link has changed is not relivant.
34726 * <script type="text/javascript">
34730 * @class Roo.menu.TextItem
34731 * @extends Roo.menu.BaseItem
34732 * Adds a static text string to a menu, usually used as either a heading or group separator.
34733 * Note: old style constructor with text is still supported.
34736 * Creates a new TextItem
34737 * @param {Object} cfg Configuration
34739 Roo.menu.TextItem = function(cfg){
34740 if (typeof(cfg) == 'string') {
34743 Roo.apply(this,cfg);
34746 Roo.menu.TextItem.superclass.constructor.call(this);
34749 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34751 * @cfg {Boolean} text Text to show on item.
34756 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34758 hideOnClick : false,
34760 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34762 itemCls : "x-menu-text",
34765 onRender : function(){
34766 var s = document.createElement("span");
34767 s.className = this.itemCls;
34768 s.innerHTML = this.text;
34770 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34774 * Ext JS Library 1.1.1
34775 * Copyright(c) 2006-2007, Ext JS, LLC.
34777 * Originally Released Under LGPL - original licence link has changed is not relivant.
34780 * <script type="text/javascript">
34784 * @class Roo.menu.Separator
34785 * @extends Roo.menu.BaseItem
34786 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34787 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34789 * @param {Object} config Configuration options
34791 Roo.menu.Separator = function(config){
34792 Roo.menu.Separator.superclass.constructor.call(this, config);
34795 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34797 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34799 itemCls : "x-menu-sep",
34801 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34803 hideOnClick : false,
34806 onRender : function(li){
34807 var s = document.createElement("span");
34808 s.className = this.itemCls;
34809 s.innerHTML = " ";
34811 li.addClass("x-menu-sep-li");
34812 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34816 * Ext JS Library 1.1.1
34817 * Copyright(c) 2006-2007, Ext JS, LLC.
34819 * Originally Released Under LGPL - original licence link has changed is not relivant.
34822 * <script type="text/javascript">
34825 * @class Roo.menu.Item
34826 * @extends Roo.menu.BaseItem
34827 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34828 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34829 * activation and click handling.
34831 * Creates a new Item
34832 * @param {Object} config Configuration options
34834 Roo.menu.Item = function(config){
34835 Roo.menu.Item.superclass.constructor.call(this, config);
34837 this.menu = Roo.menu.MenuMgr.get(this.menu);
34840 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34843 * @cfg {String} text
34844 * The text to show on the menu item.
34848 * @cfg {String} HTML to render in menu
34849 * The text to show on the menu item (HTML version).
34853 * @cfg {String} icon
34854 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34858 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34860 itemCls : "x-menu-item",
34862 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34864 canActivate : true,
34866 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34869 // doc'd in BaseItem
34873 ctype: "Roo.menu.Item",
34876 onRender : function(container, position){
34877 var el = document.createElement("a");
34878 el.hideFocus = true;
34879 el.unselectable = "on";
34880 el.href = this.href || "#";
34881 if(this.hrefTarget){
34882 el.target = this.hrefTarget;
34884 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34886 var html = this.html.length ? this.html : String.format('{0}',this.text);
34888 el.innerHTML = String.format(
34889 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34890 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34892 Roo.menu.Item.superclass.onRender.call(this, container, position);
34896 * Sets the text to display in this menu item
34897 * @param {String} text The text to display
34898 * @param {Boolean} isHTML true to indicate text is pure html.
34900 setText : function(text, isHTML){
34908 var html = this.html.length ? this.html : String.format('{0}',this.text);
34910 this.el.update(String.format(
34911 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34912 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34913 this.parentMenu.autoWidth();
34918 handleClick : function(e){
34919 if(!this.href){ // if no link defined, stop the event automatically
34922 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34926 activate : function(autoExpand){
34927 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34937 shouldDeactivate : function(e){
34938 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34939 if(this.menu && this.menu.isVisible()){
34940 return !this.menu.getEl().getRegion().contains(e.getPoint());
34948 deactivate : function(){
34949 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34954 expandMenu : function(autoActivate){
34955 if(!this.disabled && this.menu){
34956 clearTimeout(this.hideTimer);
34957 delete this.hideTimer;
34958 if(!this.menu.isVisible() && !this.showTimer){
34959 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34960 }else if (this.menu.isVisible() && autoActivate){
34961 this.menu.tryActivate(0, 1);
34967 deferExpand : function(autoActivate){
34968 delete this.showTimer;
34969 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34971 this.menu.tryActivate(0, 1);
34976 hideMenu : function(){
34977 clearTimeout(this.showTimer);
34978 delete this.showTimer;
34979 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34980 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34985 deferHide : function(){
34986 delete this.hideTimer;
34991 * Ext JS Library 1.1.1
34992 * Copyright(c) 2006-2007, Ext JS, LLC.
34994 * Originally Released Under LGPL - original licence link has changed is not relivant.
34997 * <script type="text/javascript">
35001 * @class Roo.menu.CheckItem
35002 * @extends Roo.menu.Item
35003 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35005 * Creates a new CheckItem
35006 * @param {Object} config Configuration options
35008 Roo.menu.CheckItem = function(config){
35009 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35012 * @event beforecheckchange
35013 * Fires before the checked value is set, providing an opportunity to cancel if needed
35014 * @param {Roo.menu.CheckItem} this
35015 * @param {Boolean} checked The new checked value that will be set
35017 "beforecheckchange" : true,
35019 * @event checkchange
35020 * Fires after the checked value has been set
35021 * @param {Roo.menu.CheckItem} this
35022 * @param {Boolean} checked The checked value that was set
35024 "checkchange" : true
35026 if(this.checkHandler){
35027 this.on('checkchange', this.checkHandler, this.scope);
35030 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35032 * @cfg {String} group
35033 * All check items with the same group name will automatically be grouped into a single-select
35034 * radio button group (defaults to '')
35037 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35039 itemCls : "x-menu-item x-menu-check-item",
35041 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35043 groupClass : "x-menu-group-item",
35046 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35047 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35048 * initialized with checked = true will be rendered as checked.
35053 ctype: "Roo.menu.CheckItem",
35056 onRender : function(c){
35057 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35059 this.el.addClass(this.groupClass);
35061 Roo.menu.MenuMgr.registerCheckable(this);
35063 this.checked = false;
35064 this.setChecked(true, true);
35069 destroy : function(){
35071 Roo.menu.MenuMgr.unregisterCheckable(this);
35073 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35077 * Set the checked state of this item
35078 * @param {Boolean} checked The new checked value
35079 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35081 setChecked : function(state, suppressEvent){
35082 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35083 if(this.container){
35084 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35086 this.checked = state;
35087 if(suppressEvent !== true){
35088 this.fireEvent("checkchange", this, state);
35094 handleClick : function(e){
35095 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35096 this.setChecked(!this.checked);
35098 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35102 * Ext JS Library 1.1.1
35103 * Copyright(c) 2006-2007, Ext JS, LLC.
35105 * Originally Released Under LGPL - original licence link has changed is not relivant.
35108 * <script type="text/javascript">
35112 * @class Roo.menu.DateItem
35113 * @extends Roo.menu.Adapter
35114 * A menu item that wraps the {@link Roo.DatPicker} component.
35116 * Creates a new DateItem
35117 * @param {Object} config Configuration options
35119 Roo.menu.DateItem = function(config){
35120 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35121 /** The Roo.DatePicker object @type Roo.DatePicker */
35122 this.picker = this.component;
35123 this.addEvents({select: true});
35125 this.picker.on("render", function(picker){
35126 picker.getEl().swallowEvent("click");
35127 picker.container.addClass("x-menu-date-item");
35130 this.picker.on("select", this.onSelect, this);
35133 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35135 onSelect : function(picker, date){
35136 this.fireEvent("select", this, date, picker);
35137 Roo.menu.DateItem.superclass.handleClick.call(this);
35141 * Ext JS Library 1.1.1
35142 * Copyright(c) 2006-2007, Ext JS, LLC.
35144 * Originally Released Under LGPL - original licence link has changed is not relivant.
35147 * <script type="text/javascript">
35151 * @class Roo.menu.ColorItem
35152 * @extends Roo.menu.Adapter
35153 * A menu item that wraps the {@link Roo.ColorPalette} component.
35155 * Creates a new ColorItem
35156 * @param {Object} config Configuration options
35158 Roo.menu.ColorItem = function(config){
35159 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35160 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35161 this.palette = this.component;
35162 this.relayEvents(this.palette, ["select"]);
35163 if(this.selectHandler){
35164 this.on('select', this.selectHandler, this.scope);
35167 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35169 * Ext JS Library 1.1.1
35170 * Copyright(c) 2006-2007, Ext JS, LLC.
35172 * Originally Released Under LGPL - original licence link has changed is not relivant.
35175 * <script type="text/javascript">
35180 * @class Roo.menu.DateMenu
35181 * @extends Roo.menu.Menu
35182 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35184 * Creates a new DateMenu
35185 * @param {Object} config Configuration options
35187 Roo.menu.DateMenu = function(config){
35188 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35190 var di = new Roo.menu.DateItem(config);
35193 * The {@link Roo.DatePicker} instance for this DateMenu
35196 this.picker = di.picker;
35199 * @param {DatePicker} picker
35200 * @param {Date} date
35202 this.relayEvents(di, ["select"]);
35204 this.on('beforeshow', function(){
35206 this.picker.hideMonthPicker(true);
35210 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35214 * Ext JS Library 1.1.1
35215 * Copyright(c) 2006-2007, Ext JS, LLC.
35217 * Originally Released Under LGPL - original licence link has changed is not relivant.
35220 * <script type="text/javascript">
35225 * @class Roo.menu.ColorMenu
35226 * @extends Roo.menu.Menu
35227 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35229 * Creates a new ColorMenu
35230 * @param {Object} config Configuration options
35232 Roo.menu.ColorMenu = function(config){
35233 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35235 var ci = new Roo.menu.ColorItem(config);
35238 * The {@link Roo.ColorPalette} instance for this ColorMenu
35239 * @type ColorPalette
35241 this.palette = ci.palette;
35244 * @param {ColorPalette} palette
35245 * @param {String} color
35247 this.relayEvents(ci, ["select"]);
35249 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35251 * Ext JS Library 1.1.1
35252 * Copyright(c) 2006-2007, Ext JS, LLC.
35254 * Originally Released Under LGPL - original licence link has changed is not relivant.
35257 * <script type="text/javascript">
35261 * @class Roo.form.Field
35262 * @extends Roo.BoxComponent
35263 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35265 * Creates a new Field
35266 * @param {Object} config Configuration options
35268 Roo.form.Field = function(config){
35269 Roo.form.Field.superclass.constructor.call(this, config);
35272 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35274 * @cfg {String} fieldLabel Label to use when rendering a form.
35277 * @cfg {String} qtip Mouse over tip
35281 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35283 invalidClass : "x-form-invalid",
35285 * @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")
35287 invalidText : "The value in this field is invalid",
35289 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35291 focusClass : "x-form-focus",
35293 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35294 automatic validation (defaults to "keyup").
35296 validationEvent : "keyup",
35298 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35300 validateOnBlur : true,
35302 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35304 validationDelay : 250,
35306 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35307 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35309 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35311 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35313 fieldClass : "x-form-field",
35315 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35318 ----------- ----------------------------------------------------------------------
35319 qtip Display a quick tip when the user hovers over the field
35320 title Display a default browser title attribute popup
35321 under Add a block div beneath the field containing the error text
35322 side Add an error icon to the right of the field with a popup on hover
35323 [element id] Add the error text directly to the innerHTML of the specified element
35326 msgTarget : 'qtip',
35328 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35333 * @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.
35338 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35343 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35345 inputType : undefined,
35348 * @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).
35350 tabIndex : undefined,
35353 isFormField : true,
35358 * @property {Roo.Element} fieldEl
35359 * Element Containing the rendered Field (with label etc.)
35362 * @cfg {Mixed} value A value to initialize this field with.
35367 * @cfg {String} name The field's HTML name attribute.
35370 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35374 initComponent : function(){
35375 Roo.form.Field.superclass.initComponent.call(this);
35379 * Fires when this field receives input focus.
35380 * @param {Roo.form.Field} this
35385 * Fires when this field loses input focus.
35386 * @param {Roo.form.Field} this
35390 * @event specialkey
35391 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35392 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35393 * @param {Roo.form.Field} this
35394 * @param {Roo.EventObject} e The event object
35399 * Fires just before the field blurs if the field value has changed.
35400 * @param {Roo.form.Field} this
35401 * @param {Mixed} newValue The new value
35402 * @param {Mixed} oldValue The original value
35407 * Fires after the field has been marked as invalid.
35408 * @param {Roo.form.Field} this
35409 * @param {String} msg The validation message
35414 * Fires after the field has been validated with no errors.
35415 * @param {Roo.form.Field} this
35420 * Fires after the key up
35421 * @param {Roo.form.Field} this
35422 * @param {Roo.EventObject} e The event Object
35429 * Returns the name attribute of the field if available
35430 * @return {String} name The field name
35432 getName: function(){
35433 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35437 onRender : function(ct, position){
35438 Roo.form.Field.superclass.onRender.call(this, ct, position);
35440 var cfg = this.getAutoCreate();
35442 cfg.name = this.name || this.id;
35444 if(this.inputType){
35445 cfg.type = this.inputType;
35447 this.el = ct.createChild(cfg, position);
35449 var type = this.el.dom.type;
35451 if(type == 'password'){
35454 this.el.addClass('x-form-'+type);
35457 this.el.dom.readOnly = true;
35459 if(this.tabIndex !== undefined){
35460 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35463 this.el.addClass([this.fieldClass, this.cls]);
35468 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35469 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35470 * @return {Roo.form.Field} this
35472 applyTo : function(target){
35473 this.allowDomMove = false;
35474 this.el = Roo.get(target);
35475 this.render(this.el.dom.parentNode);
35480 initValue : function(){
35481 if(this.value !== undefined){
35482 this.setValue(this.value);
35483 }else if(this.el.dom.value.length > 0){
35484 this.setValue(this.el.dom.value);
35489 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35491 isDirty : function() {
35492 if(this.disabled) {
35495 return String(this.getValue()) !== String(this.originalValue);
35499 afterRender : function(){
35500 Roo.form.Field.superclass.afterRender.call(this);
35505 fireKey : function(e){
35506 //Roo.log('field ' + e.getKey());
35507 if(e.isNavKeyPress()){
35508 this.fireEvent("specialkey", this, e);
35513 * Resets the current field value to the originally loaded value and clears any validation messages
35515 reset : function(){
35516 this.setValue(this.originalValue);
35517 this.clearInvalid();
35521 initEvents : function(){
35522 // safari killled keypress - so keydown is now used..
35523 this.el.on("keydown" , this.fireKey, this);
35524 this.el.on("focus", this.onFocus, this);
35525 this.el.on("blur", this.onBlur, this);
35526 this.el.relayEvent('keyup', this);
35528 // reference to original value for reset
35529 this.originalValue = this.getValue();
35533 onFocus : function(){
35534 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35535 this.el.addClass(this.focusClass);
35537 if(!this.hasFocus){
35538 this.hasFocus = true;
35539 this.startValue = this.getValue();
35540 this.fireEvent("focus", this);
35544 beforeBlur : Roo.emptyFn,
35547 onBlur : function(){
35549 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35550 this.el.removeClass(this.focusClass);
35552 this.hasFocus = false;
35553 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35556 var v = this.getValue();
35557 if(String(v) !== String(this.startValue)){
35558 this.fireEvent('change', this, v, this.startValue);
35560 this.fireEvent("blur", this);
35564 * Returns whether or not the field value is currently valid
35565 * @param {Boolean} preventMark True to disable marking the field invalid
35566 * @return {Boolean} True if the value is valid, else false
35568 isValid : function(preventMark){
35572 var restore = this.preventMark;
35573 this.preventMark = preventMark === true;
35574 var v = this.validateValue(this.processValue(this.getRawValue()));
35575 this.preventMark = restore;
35580 * Validates the field value
35581 * @return {Boolean} True if the value is valid, else false
35583 validate : function(){
35584 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35585 this.clearInvalid();
35591 processValue : function(value){
35596 // Subclasses should provide the validation implementation by overriding this
35597 validateValue : function(value){
35602 * Mark this field as invalid
35603 * @param {String} msg The validation message
35605 markInvalid : function(msg){
35606 if(!this.rendered || this.preventMark){ // not rendered
35609 this.el.addClass(this.invalidClass);
35610 msg = msg || this.invalidText;
35611 switch(this.msgTarget){
35613 this.el.dom.qtip = msg;
35614 this.el.dom.qclass = 'x-form-invalid-tip';
35615 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35616 Roo.QuickTips.enable();
35620 this.el.dom.title = msg;
35624 var elp = this.el.findParent('.x-form-element', 5, true);
35625 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35626 this.errorEl.setWidth(elp.getWidth(true)-20);
35628 this.errorEl.update(msg);
35629 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35632 if(!this.errorIcon){
35633 var elp = this.el.findParent('.x-form-element', 5, true);
35634 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35636 this.alignErrorIcon();
35637 this.errorIcon.dom.qtip = msg;
35638 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35639 this.errorIcon.show();
35640 this.on('resize', this.alignErrorIcon, this);
35643 var t = Roo.getDom(this.msgTarget);
35645 t.style.display = this.msgDisplay;
35648 this.fireEvent('invalid', this, msg);
35652 alignErrorIcon : function(){
35653 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35657 * Clear any invalid styles/messages for this field
35659 clearInvalid : function(){
35660 if(!this.rendered || this.preventMark){ // not rendered
35663 this.el.removeClass(this.invalidClass);
35664 switch(this.msgTarget){
35666 this.el.dom.qtip = '';
35669 this.el.dom.title = '';
35673 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35677 if(this.errorIcon){
35678 this.errorIcon.dom.qtip = '';
35679 this.errorIcon.hide();
35680 this.un('resize', this.alignErrorIcon, this);
35684 var t = Roo.getDom(this.msgTarget);
35686 t.style.display = 'none';
35689 this.fireEvent('valid', this);
35693 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35694 * @return {Mixed} value The field value
35696 getRawValue : function(){
35697 var v = this.el.getValue();
35698 if(v === this.emptyText){
35705 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35706 * @return {Mixed} value The field value
35708 getValue : function(){
35709 var v = this.el.getValue();
35710 if(v === this.emptyText || v === undefined){
35717 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35718 * @param {Mixed} value The value to set
35720 setRawValue : function(v){
35721 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35725 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35726 * @param {Mixed} value The value to set
35728 setValue : function(v){
35731 this.el.dom.value = (v === null || v === undefined ? '' : v);
35736 adjustSize : function(w, h){
35737 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35738 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35742 adjustWidth : function(tag, w){
35743 tag = tag.toLowerCase();
35744 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35745 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35746 if(tag == 'input'){
35749 if(tag = 'textarea'){
35752 }else if(Roo.isOpera){
35753 if(tag == 'input'){
35756 if(tag = 'textarea'){
35766 // anything other than normal should be considered experimental
35767 Roo.form.Field.msgFx = {
35769 show: function(msgEl, f){
35770 msgEl.setDisplayed('block');
35773 hide : function(msgEl, f){
35774 msgEl.setDisplayed(false).update('');
35779 show: function(msgEl, f){
35780 msgEl.slideIn('t', {stopFx:true});
35783 hide : function(msgEl, f){
35784 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35789 show: function(msgEl, f){
35790 msgEl.fixDisplay();
35791 msgEl.alignTo(f.el, 'tl-tr');
35792 msgEl.slideIn('l', {stopFx:true});
35795 hide : function(msgEl, f){
35796 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35801 * Ext JS Library 1.1.1
35802 * Copyright(c) 2006-2007, Ext JS, LLC.
35804 * Originally Released Under LGPL - original licence link has changed is not relivant.
35807 * <script type="text/javascript">
35812 * @class Roo.form.TextField
35813 * @extends Roo.form.Field
35814 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35815 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35817 * Creates a new TextField
35818 * @param {Object} config Configuration options
35820 Roo.form.TextField = function(config){
35821 Roo.form.TextField.superclass.constructor.call(this, config);
35825 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35826 * according to the default logic, but this event provides a hook for the developer to apply additional
35827 * logic at runtime to resize the field if needed.
35828 * @param {Roo.form.Field} this This text field
35829 * @param {Number} width The new field width
35835 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35837 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35841 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35845 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35849 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35853 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35857 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35859 disableKeyFilter : false,
35861 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35865 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35869 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35871 maxLength : Number.MAX_VALUE,
35873 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35875 minLengthText : "The minimum length for this field is {0}",
35877 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35879 maxLengthText : "The maximum length for this field is {0}",
35881 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35883 selectOnFocus : false,
35885 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35887 blankText : "This field is required",
35889 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35890 * If available, this function will be called only after the basic validators all return true, and will be passed the
35891 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35895 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35896 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35897 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35901 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35905 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35909 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35910 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35912 emptyClass : 'x-form-empty-field',
35915 initEvents : function(){
35916 Roo.form.TextField.superclass.initEvents.call(this);
35917 if(this.validationEvent == 'keyup'){
35918 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35919 this.el.on('keyup', this.filterValidation, this);
35921 else if(this.validationEvent !== false){
35922 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35924 if(this.selectOnFocus || this.emptyText){
35925 this.on("focus", this.preFocus, this);
35926 if(this.emptyText){
35927 this.on('blur', this.postBlur, this);
35928 this.applyEmptyText();
35931 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35932 this.el.on("keypress", this.filterKeys, this);
35935 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35936 this.el.on("click", this.autoSize, this);
35940 processValue : function(value){
35941 if(this.stripCharsRe){
35942 var newValue = value.replace(this.stripCharsRe, '');
35943 if(newValue !== value){
35944 this.setRawValue(newValue);
35951 filterValidation : function(e){
35952 if(!e.isNavKeyPress()){
35953 this.validationTask.delay(this.validationDelay);
35958 onKeyUp : function(e){
35959 if(!e.isNavKeyPress()){
35965 * Resets the current field value to the originally-loaded value and clears any validation messages.
35966 * Also adds emptyText and emptyClass if the original value was blank.
35968 reset : function(){
35969 Roo.form.TextField.superclass.reset.call(this);
35970 this.applyEmptyText();
35973 applyEmptyText : function(){
35974 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35975 this.setRawValue(this.emptyText);
35976 this.el.addClass(this.emptyClass);
35981 preFocus : function(){
35982 if(this.emptyText){
35983 if(this.el.dom.value == this.emptyText){
35984 this.setRawValue('');
35986 this.el.removeClass(this.emptyClass);
35988 if(this.selectOnFocus){
35989 this.el.dom.select();
35994 postBlur : function(){
35995 this.applyEmptyText();
35999 filterKeys : function(e){
36000 var k = e.getKey();
36001 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36004 var c = e.getCharCode(), cc = String.fromCharCode(c);
36005 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36008 if(!this.maskRe.test(cc)){
36013 setValue : function(v){
36014 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36015 this.el.removeClass(this.emptyClass);
36017 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36018 this.applyEmptyText();
36023 * Validates a value according to the field's validation rules and marks the field as invalid
36024 * if the validation fails
36025 * @param {Mixed} value The value to validate
36026 * @return {Boolean} True if the value is valid, else false
36028 validateValue : function(value){
36029 if(value.length < 1 || value === this.emptyText){ // if it's blank
36030 if(this.allowBlank){
36031 this.clearInvalid();
36034 this.markInvalid(this.blankText);
36038 if(value.length < this.minLength){
36039 this.markInvalid(String.format(this.minLengthText, this.minLength));
36042 if(value.length > this.maxLength){
36043 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36047 var vt = Roo.form.VTypes;
36048 if(!vt[this.vtype](value, this)){
36049 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36053 if(typeof this.validator == "function"){
36054 var msg = this.validator(value);
36056 this.markInvalid(msg);
36060 if(this.regex && !this.regex.test(value)){
36061 this.markInvalid(this.regexText);
36068 * Selects text in this field
36069 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36070 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36072 selectText : function(start, end){
36073 var v = this.getRawValue();
36075 start = start === undefined ? 0 : start;
36076 end = end === undefined ? v.length : end;
36077 var d = this.el.dom;
36078 if(d.setSelectionRange){
36079 d.setSelectionRange(start, end);
36080 }else if(d.createTextRange){
36081 var range = d.createTextRange();
36082 range.moveStart("character", start);
36083 range.moveEnd("character", v.length-end);
36090 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36091 * This only takes effect if grow = true, and fires the autosize event.
36093 autoSize : function(){
36094 if(!this.grow || !this.rendered){
36098 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36101 var v = el.dom.value;
36102 var d = document.createElement('div');
36103 d.appendChild(document.createTextNode(v));
36107 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36108 this.el.setWidth(w);
36109 this.fireEvent("autosize", this, w);
36113 * Ext JS Library 1.1.1
36114 * Copyright(c) 2006-2007, Ext JS, LLC.
36116 * Originally Released Under LGPL - original licence link has changed is not relivant.
36119 * <script type="text/javascript">
36123 * @class Roo.form.Hidden
36124 * @extends Roo.form.TextField
36125 * Simple Hidden element used on forms
36127 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36130 * Creates a new Hidden form element.
36131 * @param {Object} config Configuration options
36136 // easy hidden field...
36137 Roo.form.Hidden = function(config){
36138 Roo.form.Hidden.superclass.constructor.call(this, config);
36141 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36143 inputType: 'hidden',
36146 labelSeparator: '',
36148 itemCls : 'x-form-item-display-none'
36156 * Ext JS Library 1.1.1
36157 * Copyright(c) 2006-2007, Ext JS, LLC.
36159 * Originally Released Under LGPL - original licence link has changed is not relivant.
36162 * <script type="text/javascript">
36166 * @class Roo.form.TriggerField
36167 * @extends Roo.form.TextField
36168 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36169 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36170 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36171 * for which you can provide a custom implementation. For example:
36173 var trigger = new Roo.form.TriggerField();
36174 trigger.onTriggerClick = myTriggerFn;
36175 trigger.applyTo('my-field');
36178 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36179 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36180 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36181 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36183 * Create a new TriggerField.
36184 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36185 * to the base TextField)
36187 Roo.form.TriggerField = function(config){
36188 this.mimicing = false;
36189 Roo.form.TriggerField.superclass.constructor.call(this, config);
36192 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36194 * @cfg {String} triggerClass A CSS class to apply to the trigger
36197 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36198 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36200 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36202 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36206 /** @cfg {Boolean} grow @hide */
36207 /** @cfg {Number} growMin @hide */
36208 /** @cfg {Number} growMax @hide */
36214 autoSize: Roo.emptyFn,
36218 deferHeight : true,
36221 actionMode : 'wrap',
36223 onResize : function(w, h){
36224 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36225 if(typeof w == 'number'){
36226 var x = w - this.trigger.getWidth();
36227 this.el.setWidth(this.adjustWidth('input', x));
36228 this.trigger.setStyle('left', x+'px');
36233 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36236 getResizeEl : function(){
36241 getPositionEl : function(){
36246 alignErrorIcon : function(){
36247 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36251 onRender : function(ct, position){
36252 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36253 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36254 this.trigger = this.wrap.createChild(this.triggerConfig ||
36255 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36256 if(this.hideTrigger){
36257 this.trigger.setDisplayed(false);
36259 this.initTrigger();
36261 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36266 initTrigger : function(){
36267 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36268 this.trigger.addClassOnOver('x-form-trigger-over');
36269 this.trigger.addClassOnClick('x-form-trigger-click');
36273 onDestroy : function(){
36275 this.trigger.removeAllListeners();
36276 this.trigger.remove();
36279 this.wrap.remove();
36281 Roo.form.TriggerField.superclass.onDestroy.call(this);
36285 onFocus : function(){
36286 Roo.form.TriggerField.superclass.onFocus.call(this);
36287 if(!this.mimicing){
36288 this.wrap.addClass('x-trigger-wrap-focus');
36289 this.mimicing = true;
36290 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36291 if(this.monitorTab){
36292 this.el.on("keydown", this.checkTab, this);
36298 checkTab : function(e){
36299 if(e.getKey() == e.TAB){
36300 this.triggerBlur();
36305 onBlur : function(){
36310 mimicBlur : function(e, t){
36311 if(!this.wrap.contains(t) && this.validateBlur()){
36312 this.triggerBlur();
36317 triggerBlur : function(){
36318 this.mimicing = false;
36319 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36320 if(this.monitorTab){
36321 this.el.un("keydown", this.checkTab, this);
36323 this.wrap.removeClass('x-trigger-wrap-focus');
36324 Roo.form.TriggerField.superclass.onBlur.call(this);
36328 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36329 validateBlur : function(e, t){
36334 onDisable : function(){
36335 Roo.form.TriggerField.superclass.onDisable.call(this);
36337 this.wrap.addClass('x-item-disabled');
36342 onEnable : function(){
36343 Roo.form.TriggerField.superclass.onEnable.call(this);
36345 this.wrap.removeClass('x-item-disabled');
36350 onShow : function(){
36351 var ae = this.getActionEl();
36354 ae.dom.style.display = '';
36355 ae.dom.style.visibility = 'visible';
36361 onHide : function(){
36362 var ae = this.getActionEl();
36363 ae.dom.style.display = 'none';
36367 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36368 * by an implementing function.
36370 * @param {EventObject} e
36372 onTriggerClick : Roo.emptyFn
36375 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36376 // to be extended by an implementing class. For an example of implementing this class, see the custom
36377 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36378 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36379 initComponent : function(){
36380 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36382 this.triggerConfig = {
36383 tag:'span', cls:'x-form-twin-triggers', cn:[
36384 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36385 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36389 getTrigger : function(index){
36390 return this.triggers[index];
36393 initTrigger : function(){
36394 var ts = this.trigger.select('.x-form-trigger', true);
36395 this.wrap.setStyle('overflow', 'hidden');
36396 var triggerField = this;
36397 ts.each(function(t, all, index){
36398 t.hide = function(){
36399 var w = triggerField.wrap.getWidth();
36400 this.dom.style.display = 'none';
36401 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36403 t.show = function(){
36404 var w = triggerField.wrap.getWidth();
36405 this.dom.style.display = '';
36406 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36408 var triggerIndex = 'Trigger'+(index+1);
36410 if(this['hide'+triggerIndex]){
36411 t.dom.style.display = 'none';
36413 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36414 t.addClassOnOver('x-form-trigger-over');
36415 t.addClassOnClick('x-form-trigger-click');
36417 this.triggers = ts.elements;
36420 onTrigger1Click : Roo.emptyFn,
36421 onTrigger2Click : Roo.emptyFn
36424 * Ext JS Library 1.1.1
36425 * Copyright(c) 2006-2007, Ext JS, LLC.
36427 * Originally Released Under LGPL - original licence link has changed is not relivant.
36430 * <script type="text/javascript">
36434 * @class Roo.form.TextArea
36435 * @extends Roo.form.TextField
36436 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36437 * support for auto-sizing.
36439 * Creates a new TextArea
36440 * @param {Object} config Configuration options
36442 Roo.form.TextArea = function(config){
36443 Roo.form.TextArea.superclass.constructor.call(this, config);
36444 // these are provided exchanges for backwards compat
36445 // minHeight/maxHeight were replaced by growMin/growMax to be
36446 // compatible with TextField growing config values
36447 if(this.minHeight !== undefined){
36448 this.growMin = this.minHeight;
36450 if(this.maxHeight !== undefined){
36451 this.growMax = this.maxHeight;
36455 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36457 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36461 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36465 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36466 * in the field (equivalent to setting overflow: hidden, defaults to false)
36468 preventScrollbars: false,
36470 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36471 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36475 onRender : function(ct, position){
36477 this.defaultAutoCreate = {
36479 style:"width:300px;height:60px;",
36480 autocomplete: "off"
36483 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36485 this.textSizeEl = Roo.DomHelper.append(document.body, {
36486 tag: "pre", cls: "x-form-grow-sizer"
36488 if(this.preventScrollbars){
36489 this.el.setStyle("overflow", "hidden");
36491 this.el.setHeight(this.growMin);
36495 onDestroy : function(){
36496 if(this.textSizeEl){
36497 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36499 Roo.form.TextArea.superclass.onDestroy.call(this);
36503 onKeyUp : function(e){
36504 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36510 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36511 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36513 autoSize : function(){
36514 if(!this.grow || !this.textSizeEl){
36518 var v = el.dom.value;
36519 var ts = this.textSizeEl;
36522 ts.appendChild(document.createTextNode(v));
36525 Roo.fly(ts).setWidth(this.el.getWidth());
36527 v = "  ";
36530 v = v.replace(/\n/g, '<p> </p>');
36532 v += " \n ";
36535 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36536 if(h != this.lastHeight){
36537 this.lastHeight = h;
36538 this.el.setHeight(h);
36539 this.fireEvent("autosize", this, h);
36544 * Ext JS Library 1.1.1
36545 * Copyright(c) 2006-2007, Ext JS, LLC.
36547 * Originally Released Under LGPL - original licence link has changed is not relivant.
36550 * <script type="text/javascript">
36555 * @class Roo.form.NumberField
36556 * @extends Roo.form.TextField
36557 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36559 * Creates a new NumberField
36560 * @param {Object} config Configuration options
36562 Roo.form.NumberField = function(config){
36563 Roo.form.NumberField.superclass.constructor.call(this, config);
36566 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36568 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36570 fieldClass: "x-form-field x-form-num-field",
36572 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36574 allowDecimals : true,
36576 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36578 decimalSeparator : ".",
36580 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36582 decimalPrecision : 2,
36584 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36586 allowNegative : true,
36588 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36590 minValue : Number.NEGATIVE_INFINITY,
36592 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36594 maxValue : Number.MAX_VALUE,
36596 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36598 minText : "The minimum value for this field is {0}",
36600 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36602 maxText : "The maximum value for this field is {0}",
36604 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36605 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36607 nanText : "{0} is not a valid number",
36610 initEvents : function(){
36611 Roo.form.NumberField.superclass.initEvents.call(this);
36612 var allowed = "0123456789";
36613 if(this.allowDecimals){
36614 allowed += this.decimalSeparator;
36616 if(this.allowNegative){
36619 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36620 var keyPress = function(e){
36621 var k = e.getKey();
36622 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36625 var c = e.getCharCode();
36626 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36630 this.el.on("keypress", keyPress, this);
36634 validateValue : function(value){
36635 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36638 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36641 var num = this.parseValue(value);
36643 this.markInvalid(String.format(this.nanText, value));
36646 if(num < this.minValue){
36647 this.markInvalid(String.format(this.minText, this.minValue));
36650 if(num > this.maxValue){
36651 this.markInvalid(String.format(this.maxText, this.maxValue));
36657 getValue : function(){
36658 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36662 parseValue : function(value){
36663 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36664 return isNaN(value) ? '' : value;
36668 fixPrecision : function(value){
36669 var nan = isNaN(value);
36670 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36671 return nan ? '' : value;
36673 return parseFloat(value).toFixed(this.decimalPrecision);
36676 setValue : function(v){
36677 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36681 decimalPrecisionFcn : function(v){
36682 return Math.floor(v);
36685 beforeBlur : function(){
36686 var v = this.parseValue(this.getRawValue());
36688 this.setValue(this.fixPrecision(v));
36693 * Ext JS Library 1.1.1
36694 * Copyright(c) 2006-2007, Ext JS, LLC.
36696 * Originally Released Under LGPL - original licence link has changed is not relivant.
36699 * <script type="text/javascript">
36703 * @class Roo.form.DateField
36704 * @extends Roo.form.TriggerField
36705 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36707 * Create a new DateField
36708 * @param {Object} config
36710 Roo.form.DateField = function(config){
36711 Roo.form.DateField.superclass.constructor.call(this, config);
36717 * Fires when a date is selected
36718 * @param {Roo.form.DateField} combo This combo box
36719 * @param {Date} date The date selected
36726 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36727 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36728 this.ddMatch = null;
36729 if(this.disabledDates){
36730 var dd = this.disabledDates;
36732 for(var i = 0; i < dd.length; i++){
36734 if(i != dd.length-1) re += "|";
36736 this.ddMatch = new RegExp(re + ")");
36740 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36742 * @cfg {String} format
36743 * The default date format string which can be overriden for localization support. The format must be
36744 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36748 * @cfg {String} altFormats
36749 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36750 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36752 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36754 * @cfg {Array} disabledDays
36755 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36757 disabledDays : null,
36759 * @cfg {String} disabledDaysText
36760 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36762 disabledDaysText : "Disabled",
36764 * @cfg {Array} disabledDates
36765 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36766 * expression so they are very powerful. Some examples:
36768 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36769 * <li>["03/08", "09/16"] would disable those days for every year</li>
36770 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36771 * <li>["03/../2006"] would disable every day in March 2006</li>
36772 * <li>["^03"] would disable every day in every March</li>
36774 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36775 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36777 disabledDates : null,
36779 * @cfg {String} disabledDatesText
36780 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36782 disabledDatesText : "Disabled",
36784 * @cfg {Date/String} minValue
36785 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36786 * valid format (defaults to null).
36790 * @cfg {Date/String} maxValue
36791 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36792 * valid format (defaults to null).
36796 * @cfg {String} minText
36797 * The error text to display when the date in the cell is before minValue (defaults to
36798 * 'The date in this field must be after {minValue}').
36800 minText : "The date in this field must be equal to or after {0}",
36802 * @cfg {String} maxText
36803 * The error text to display when the date in the cell is after maxValue (defaults to
36804 * 'The date in this field must be before {maxValue}').
36806 maxText : "The date in this field must be equal to or before {0}",
36808 * @cfg {String} invalidText
36809 * The error text to display when the date in the field is invalid (defaults to
36810 * '{value} is not a valid date - it must be in the format {format}').
36812 invalidText : "{0} is not a valid date - it must be in the format {1}",
36814 * @cfg {String} triggerClass
36815 * An additional CSS class used to style the trigger button. The trigger will always get the
36816 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36817 * which displays a calendar icon).
36819 triggerClass : 'x-form-date-trigger',
36823 * @cfg {bool} useIso
36824 * if enabled, then the date field will use a hidden field to store the
36825 * real value as iso formated date. default (false)
36829 * @cfg {String/Object} autoCreate
36830 * A DomHelper element spec, or true for a default element spec (defaults to
36831 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36834 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36837 hiddenField: false,
36839 onRender : function(ct, position)
36841 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36843 this.el.dom.removeAttribute('name');
36844 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36846 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36847 // prevent input submission
36848 this.hiddenName = this.name;
36855 validateValue : function(value)
36857 value = this.formatDate(value);
36858 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36861 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36864 var svalue = value;
36865 value = this.parseDate(value);
36867 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36870 var time = value.getTime();
36871 if(this.minValue && time < this.minValue.getTime()){
36872 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36875 if(this.maxValue && time > this.maxValue.getTime()){
36876 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36879 if(this.disabledDays){
36880 var day = value.getDay();
36881 for(var i = 0; i < this.disabledDays.length; i++) {
36882 if(day === this.disabledDays[i]){
36883 this.markInvalid(this.disabledDaysText);
36888 var fvalue = this.formatDate(value);
36889 if(this.ddMatch && this.ddMatch.test(fvalue)){
36890 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36897 // Provides logic to override the default TriggerField.validateBlur which just returns true
36898 validateBlur : function(){
36899 return !this.menu || !this.menu.isVisible();
36903 * Returns the current date value of the date field.
36904 * @return {Date} The date value
36906 getValue : function(){
36908 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36912 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36913 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36914 * (the default format used is "m/d/y").
36917 //All of these calls set the same date value (May 4, 2006)
36919 //Pass a date object:
36920 var dt = new Date('5/4/06');
36921 dateField.setValue(dt);
36923 //Pass a date string (default format):
36924 dateField.setValue('5/4/06');
36926 //Pass a date string (custom format):
36927 dateField.format = 'Y-m-d';
36928 dateField.setValue('2006-5-4');
36930 * @param {String/Date} date The date or valid date string
36932 setValue : function(date){
36933 if (this.hiddenField) {
36934 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36936 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36940 parseDate : function(value){
36941 if(!value || value instanceof Date){
36944 var v = Date.parseDate(value, this.format);
36945 if(!v && this.altFormats){
36946 if(!this.altFormatsArray){
36947 this.altFormatsArray = this.altFormats.split("|");
36949 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36950 v = Date.parseDate(value, this.altFormatsArray[i]);
36957 formatDate : function(date, fmt){
36958 return (!date || !(date instanceof Date)) ?
36959 date : date.dateFormat(fmt || this.format);
36964 select: function(m, d){
36966 this.fireEvent('select', this, d);
36968 show : function(){ // retain focus styling
36972 this.focus.defer(10, this);
36973 var ml = this.menuListeners;
36974 this.menu.un("select", ml.select, this);
36975 this.menu.un("show", ml.show, this);
36976 this.menu.un("hide", ml.hide, this);
36981 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36982 onTriggerClick : function(){
36986 if(this.menu == null){
36987 this.menu = new Roo.menu.DateMenu();
36989 Roo.apply(this.menu.picker, {
36990 showClear: this.allowBlank,
36991 minDate : this.minValue,
36992 maxDate : this.maxValue,
36993 disabledDatesRE : this.ddMatch,
36994 disabledDatesText : this.disabledDatesText,
36995 disabledDays : this.disabledDays,
36996 disabledDaysText : this.disabledDaysText,
36997 format : this.format,
36998 minText : String.format(this.minText, this.formatDate(this.minValue)),
36999 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37001 this.menu.on(Roo.apply({}, this.menuListeners, {
37004 this.menu.picker.setValue(this.getValue() || new Date());
37005 this.menu.show(this.el, "tl-bl?");
37008 beforeBlur : function(){
37009 var v = this.parseDate(this.getRawValue());
37015 /** @cfg {Boolean} grow @hide */
37016 /** @cfg {Number} growMin @hide */
37017 /** @cfg {Number} growMax @hide */
37024 * Ext JS Library 1.1.1
37025 * Copyright(c) 2006-2007, Ext JS, LLC.
37027 * Originally Released Under LGPL - original licence link has changed is not relivant.
37030 * <script type="text/javascript">
37035 * @class Roo.form.ComboBox
37036 * @extends Roo.form.TriggerField
37037 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37039 * Create a new ComboBox.
37040 * @param {Object} config Configuration options
37042 Roo.form.ComboBox = function(config){
37043 Roo.form.ComboBox.superclass.constructor.call(this, config);
37047 * Fires when the dropdown list is expanded
37048 * @param {Roo.form.ComboBox} combo This combo box
37053 * Fires when the dropdown list is collapsed
37054 * @param {Roo.form.ComboBox} combo This combo box
37058 * @event beforeselect
37059 * Fires before a list item is selected. Return false to cancel the selection.
37060 * @param {Roo.form.ComboBox} combo This combo box
37061 * @param {Roo.data.Record} record The data record returned from the underlying store
37062 * @param {Number} index The index of the selected item in the dropdown list
37064 'beforeselect' : true,
37067 * Fires when a list item is selected
37068 * @param {Roo.form.ComboBox} combo This combo box
37069 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37070 * @param {Number} index The index of the selected item in the dropdown list
37074 * @event beforequery
37075 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37076 * The event object passed has these properties:
37077 * @param {Roo.form.ComboBox} combo This combo box
37078 * @param {String} query The query
37079 * @param {Boolean} forceAll true to force "all" query
37080 * @param {Boolean} cancel true to cancel the query
37081 * @param {Object} e The query event object
37083 'beforequery': true,
37086 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37087 * @param {Roo.form.ComboBox} combo This combo box
37092 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37093 * @param {Roo.form.ComboBox} combo This combo box
37094 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37100 if(this.transform){
37101 this.allowDomMove = false;
37102 var s = Roo.getDom(this.transform);
37103 if(!this.hiddenName){
37104 this.hiddenName = s.name;
37107 this.mode = 'local';
37108 var d = [], opts = s.options;
37109 for(var i = 0, len = opts.length;i < len; i++){
37111 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37113 this.value = value;
37115 d.push([value, o.text]);
37117 this.store = new Roo.data.SimpleStore({
37119 fields: ['value', 'text'],
37122 this.valueField = 'value';
37123 this.displayField = 'text';
37125 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37126 if(!this.lazyRender){
37127 this.target = true;
37128 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37129 s.parentNode.removeChild(s); // remove it
37130 this.render(this.el.parentNode);
37132 s.parentNode.removeChild(s); // remove it
37137 this.store = Roo.factory(this.store, Roo.data);
37140 this.selectedIndex = -1;
37141 if(this.mode == 'local'){
37142 if(config.queryDelay === undefined){
37143 this.queryDelay = 10;
37145 if(config.minChars === undefined){
37151 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37153 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37156 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37157 * rendering into an Roo.Editor, defaults to false)
37160 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37161 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37164 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37167 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37168 * the dropdown list (defaults to undefined, with no header element)
37172 * @cfg {String/Roo.Template} tpl The template to use to render the output
37176 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37178 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37180 listWidth: undefined,
37182 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37183 * mode = 'remote' or 'text' if mode = 'local')
37185 displayField: undefined,
37187 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37188 * mode = 'remote' or 'value' if mode = 'local').
37189 * Note: use of a valueField requires the user make a selection
37190 * in order for a value to be mapped.
37192 valueField: undefined,
37194 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37195 * field's data value (defaults to the underlying DOM element's name)
37197 hiddenName: undefined,
37199 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37203 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37205 selectedClass: 'x-combo-selected',
37207 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37208 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37209 * which displays a downward arrow icon).
37211 triggerClass : 'x-form-arrow-trigger',
37213 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37217 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37218 * anchor positions (defaults to 'tl-bl')
37220 listAlign: 'tl-bl?',
37222 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37226 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37227 * query specified by the allQuery config option (defaults to 'query')
37229 triggerAction: 'query',
37231 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37232 * (defaults to 4, does not apply if editable = false)
37236 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37237 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37241 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37242 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37246 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37247 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37251 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37252 * when editable = true (defaults to false)
37254 selectOnFocus:false,
37256 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37258 queryParam: 'query',
37260 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37261 * when mode = 'remote' (defaults to 'Loading...')
37263 loadingText: 'Loading...',
37265 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37269 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37273 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37274 * traditional select (defaults to true)
37278 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37282 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37286 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37287 * listWidth has a higher value)
37291 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37292 * allow the user to set arbitrary text into the field (defaults to false)
37294 forceSelection:false,
37296 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37297 * if typeAhead = true (defaults to 250)
37299 typeAheadDelay : 250,
37301 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37302 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37304 valueNotFoundText : undefined,
37306 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37308 blockFocus : false,
37311 * @cfg {Boolean} disableClear Disable showing of clear button.
37313 disableClear : false,
37315 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37317 alwaysQuery : false,
37325 onRender : function(ct, position){
37326 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37327 if(this.hiddenName){
37328 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37330 this.hiddenField.value =
37331 this.hiddenValue !== undefined ? this.hiddenValue :
37332 this.value !== undefined ? this.value : '';
37334 // prevent input submission
37335 this.el.dom.removeAttribute('name');
37338 this.el.dom.setAttribute('autocomplete', 'off');
37341 var cls = 'x-combo-list';
37343 this.list = new Roo.Layer({
37344 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37347 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37348 this.list.setWidth(lw);
37349 this.list.swallowEvent('mousewheel');
37350 this.assetHeight = 0;
37353 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37354 this.assetHeight += this.header.getHeight();
37357 this.innerList = this.list.createChild({cls:cls+'-inner'});
37358 this.innerList.on('mouseover', this.onViewOver, this);
37359 this.innerList.on('mousemove', this.onViewMove, this);
37360 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37362 if(this.allowBlank && !this.pageSize && !this.disableClear){
37363 this.footer = this.list.createChild({cls:cls+'-ft'});
37364 this.pageTb = new Roo.Toolbar(this.footer);
37368 this.footer = this.list.createChild({cls:cls+'-ft'});
37369 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37370 {pageSize: this.pageSize});
37374 if (this.pageTb && this.allowBlank && !this.disableClear) {
37376 this.pageTb.add(new Roo.Toolbar.Fill(), {
37377 cls: 'x-btn-icon x-btn-clear',
37379 handler: function()
37382 _this.clearValue();
37383 _this.onSelect(false, -1);
37388 this.assetHeight += this.footer.getHeight();
37393 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37396 this.view = new Roo.View(this.innerList, this.tpl, {
37397 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37400 this.view.on('click', this.onViewClick, this);
37402 this.store.on('beforeload', this.onBeforeLoad, this);
37403 this.store.on('load', this.onLoad, this);
37404 this.store.on('loadexception', this.collapse, this);
37406 if(this.resizable){
37407 this.resizer = new Roo.Resizable(this.list, {
37408 pinned:true, handles:'se'
37410 this.resizer.on('resize', function(r, w, h){
37411 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37412 this.listWidth = w;
37413 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37414 this.restrictHeight();
37416 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37418 if(!this.editable){
37419 this.editable = true;
37420 this.setEditable(false);
37424 if (typeof(this.events.add.listeners) != 'undefined') {
37426 this.addicon = this.wrap.createChild(
37427 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37429 this.addicon.on('click', function(e) {
37430 this.fireEvent('add', this);
37433 if (typeof(this.events.edit.listeners) != 'undefined') {
37435 this.editicon = this.wrap.createChild(
37436 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37437 if (this.addicon) {
37438 this.editicon.setStyle('margin-left', '40px');
37440 this.editicon.on('click', function(e) {
37442 // we fire even if inothing is selected..
37443 this.fireEvent('edit', this, this.lastData );
37453 initEvents : function(){
37454 Roo.form.ComboBox.superclass.initEvents.call(this);
37456 this.keyNav = new Roo.KeyNav(this.el, {
37457 "up" : function(e){
37458 this.inKeyMode = true;
37462 "down" : function(e){
37463 if(!this.isExpanded()){
37464 this.onTriggerClick();
37466 this.inKeyMode = true;
37471 "enter" : function(e){
37472 this.onViewClick();
37476 "esc" : function(e){
37480 "tab" : function(e){
37481 this.onViewClick(false);
37487 doRelay : function(foo, bar, hname){
37488 if(hname == 'down' || this.scope.isExpanded()){
37489 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37496 this.queryDelay = Math.max(this.queryDelay || 10,
37497 this.mode == 'local' ? 10 : 250);
37498 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37499 if(this.typeAhead){
37500 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37502 if(this.editable !== false){
37503 this.el.on("keyup", this.onKeyUp, this);
37505 if(this.forceSelection){
37506 this.on('blur', this.doForce, this);
37510 onDestroy : function(){
37512 this.view.setStore(null);
37513 this.view.el.removeAllListeners();
37514 this.view.el.remove();
37515 this.view.purgeListeners();
37518 this.list.destroy();
37521 this.store.un('beforeload', this.onBeforeLoad, this);
37522 this.store.un('load', this.onLoad, this);
37523 this.store.un('loadexception', this.collapse, this);
37525 Roo.form.ComboBox.superclass.onDestroy.call(this);
37529 fireKey : function(e){
37530 if(e.isNavKeyPress() && !this.list.isVisible()){
37531 this.fireEvent("specialkey", this, e);
37536 onResize: function(w, h){
37537 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37539 if(typeof w != 'number'){
37540 // we do not handle it!?!?
37543 var tw = this.trigger.getWidth();
37544 tw += this.addicon ? this.addicon.getWidth() : 0;
37545 tw += this.editicon ? this.editicon.getWidth() : 0;
37547 this.el.setWidth( this.adjustWidth('input', x));
37549 this.trigger.setStyle('left', x+'px');
37551 if(this.list && this.listWidth === undefined){
37552 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37553 this.list.setWidth(lw);
37554 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37562 * Allow or prevent the user from directly editing the field text. If false is passed,
37563 * the user will only be able to select from the items defined in the dropdown list. This method
37564 * is the runtime equivalent of setting the 'editable' config option at config time.
37565 * @param {Boolean} value True to allow the user to directly edit the field text
37567 setEditable : function(value){
37568 if(value == this.editable){
37571 this.editable = value;
37573 this.el.dom.setAttribute('readOnly', true);
37574 this.el.on('mousedown', this.onTriggerClick, this);
37575 this.el.addClass('x-combo-noedit');
37577 this.el.dom.setAttribute('readOnly', false);
37578 this.el.un('mousedown', this.onTriggerClick, this);
37579 this.el.removeClass('x-combo-noedit');
37584 onBeforeLoad : function(){
37585 if(!this.hasFocus){
37588 this.innerList.update(this.loadingText ?
37589 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37590 this.restrictHeight();
37591 this.selectedIndex = -1;
37595 onLoad : function(){
37596 if(!this.hasFocus){
37599 if(this.store.getCount() > 0){
37601 this.restrictHeight();
37602 if(this.lastQuery == this.allQuery){
37604 this.el.dom.select();
37606 if(!this.selectByValue(this.value, true)){
37607 this.select(0, true);
37611 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37612 this.taTask.delay(this.typeAheadDelay);
37616 this.onEmptyResults();
37622 onTypeAhead : function(){
37623 if(this.store.getCount() > 0){
37624 var r = this.store.getAt(0);
37625 var newValue = r.data[this.displayField];
37626 var len = newValue.length;
37627 var selStart = this.getRawValue().length;
37628 if(selStart != len){
37629 this.setRawValue(newValue);
37630 this.selectText(selStart, newValue.length);
37636 onSelect : function(record, index){
37637 if(this.fireEvent('beforeselect', this, record, index) !== false){
37638 this.setFromData(index > -1 ? record.data : false);
37640 this.fireEvent('select', this, record, index);
37645 * Returns the currently selected field value or empty string if no value is set.
37646 * @return {String} value The selected value
37648 getValue : function(){
37649 if(this.valueField){
37650 return typeof this.value != 'undefined' ? this.value : '';
37652 return Roo.form.ComboBox.superclass.getValue.call(this);
37657 * Clears any text/value currently set in the field
37659 clearValue : function(){
37660 if(this.hiddenField){
37661 this.hiddenField.value = '';
37664 this.setRawValue('');
37665 this.lastSelectionText = '';
37666 this.applyEmptyText();
37670 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37671 * will be displayed in the field. If the value does not match the data value of an existing item,
37672 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37673 * Otherwise the field will be blank (although the value will still be set).
37674 * @param {String} value The value to match
37676 setValue : function(v){
37678 if(this.valueField){
37679 var r = this.findRecord(this.valueField, v);
37681 text = r.data[this.displayField];
37682 }else if(this.valueNotFoundText !== undefined){
37683 text = this.valueNotFoundText;
37686 this.lastSelectionText = text;
37687 if(this.hiddenField){
37688 this.hiddenField.value = v;
37690 Roo.form.ComboBox.superclass.setValue.call(this, text);
37694 * @property {Object} the last set data for the element
37699 * Sets the value of the field based on a object which is related to the record format for the store.
37700 * @param {Object} value the value to set as. or false on reset?
37702 setFromData : function(o){
37703 var dv = ''; // display value
37704 var vv = ''; // value value..
37706 if (this.displayField) {
37707 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37709 // this is an error condition!!!
37710 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37713 if(this.valueField){
37714 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37716 if(this.hiddenField){
37717 this.hiddenField.value = vv;
37719 this.lastSelectionText = dv;
37720 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37724 // no hidden field.. - we store the value in 'value', but still display
37725 // display field!!!!
37726 this.lastSelectionText = dv;
37727 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37733 reset : function(){
37734 // overridden so that last data is reset..
37735 this.setValue(this.originalValue);
37736 this.clearInvalid();
37737 this.lastData = false;
37740 findRecord : function(prop, value){
37742 if(this.store.getCount() > 0){
37743 this.store.each(function(r){
37744 if(r.data[prop] == value){
37754 onViewMove : function(e, t){
37755 this.inKeyMode = false;
37759 onViewOver : function(e, t){
37760 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37763 var item = this.view.findItemFromChild(t);
37765 var index = this.view.indexOf(item);
37766 this.select(index, false);
37771 onViewClick : function(doFocus){
37772 var index = this.view.getSelectedIndexes()[0];
37773 var r = this.store.getAt(index);
37775 this.onSelect(r, index);
37777 if(doFocus !== false && !this.blockFocus){
37783 restrictHeight : function(){
37784 this.innerList.dom.style.height = '';
37785 var inner = this.innerList.dom;
37786 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37787 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37788 this.list.beginUpdate();
37789 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37790 this.list.alignTo(this.el, this.listAlign);
37791 this.list.endUpdate();
37795 onEmptyResults : function(){
37800 * Returns true if the dropdown list is expanded, else false.
37802 isExpanded : function(){
37803 return this.list.isVisible();
37807 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37808 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37809 * @param {String} value The data value of the item to select
37810 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37811 * selected item if it is not currently in view (defaults to true)
37812 * @return {Boolean} True if the value matched an item in the list, else false
37814 selectByValue : function(v, scrollIntoView){
37815 if(v !== undefined && v !== null){
37816 var r = this.findRecord(this.valueField || this.displayField, v);
37818 this.select(this.store.indexOf(r), scrollIntoView);
37826 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37827 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37828 * @param {Number} index The zero-based index of the list item to select
37829 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37830 * selected item if it is not currently in view (defaults to true)
37832 select : function(index, scrollIntoView){
37833 this.selectedIndex = index;
37834 this.view.select(index);
37835 if(scrollIntoView !== false){
37836 var el = this.view.getNode(index);
37838 this.innerList.scrollChildIntoView(el, false);
37844 selectNext : function(){
37845 var ct = this.store.getCount();
37847 if(this.selectedIndex == -1){
37849 }else if(this.selectedIndex < ct-1){
37850 this.select(this.selectedIndex+1);
37856 selectPrev : function(){
37857 var ct = this.store.getCount();
37859 if(this.selectedIndex == -1){
37861 }else if(this.selectedIndex != 0){
37862 this.select(this.selectedIndex-1);
37868 onKeyUp : function(e){
37869 if(this.editable !== false && !e.isSpecialKey()){
37870 this.lastKey = e.getKey();
37871 this.dqTask.delay(this.queryDelay);
37876 validateBlur : function(){
37877 return !this.list || !this.list.isVisible();
37881 initQuery : function(){
37882 this.doQuery(this.getRawValue());
37886 doForce : function(){
37887 if(this.el.dom.value.length > 0){
37888 this.el.dom.value =
37889 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37890 this.applyEmptyText();
37895 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37896 * query allowing the query action to be canceled if needed.
37897 * @param {String} query The SQL query to execute
37898 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37899 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37900 * saved in the current store (defaults to false)
37902 doQuery : function(q, forceAll){
37903 if(q === undefined || q === null){
37908 forceAll: forceAll,
37912 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37916 forceAll = qe.forceAll;
37917 if(forceAll === true || (q.length >= this.minChars)){
37918 if(this.lastQuery != q || this.alwaysQuery){
37919 this.lastQuery = q;
37920 if(this.mode == 'local'){
37921 this.selectedIndex = -1;
37923 this.store.clearFilter();
37925 this.store.filter(this.displayField, q);
37929 this.store.baseParams[this.queryParam] = q;
37931 params: this.getParams(q)
37936 this.selectedIndex = -1;
37943 getParams : function(q){
37945 //p[this.queryParam] = q;
37948 p.limit = this.pageSize;
37954 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37956 collapse : function(){
37957 if(!this.isExpanded()){
37961 Roo.get(document).un('mousedown', this.collapseIf, this);
37962 Roo.get(document).un('mousewheel', this.collapseIf, this);
37963 if (!this.editable) {
37964 Roo.get(document).un('keydown', this.listKeyPress, this);
37966 this.fireEvent('collapse', this);
37970 collapseIf : function(e){
37971 if(!e.within(this.wrap) && !e.within(this.list)){
37977 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37979 expand : function(){
37980 if(this.isExpanded() || !this.hasFocus){
37983 this.list.alignTo(this.el, this.listAlign);
37985 Roo.get(document).on('mousedown', this.collapseIf, this);
37986 Roo.get(document).on('mousewheel', this.collapseIf, this);
37987 if (!this.editable) {
37988 Roo.get(document).on('keydown', this.listKeyPress, this);
37991 this.fireEvent('expand', this);
37995 // Implements the default empty TriggerField.onTriggerClick function
37996 onTriggerClick : function(){
38000 if(this.isExpanded()){
38002 if (!this.blockFocus) {
38007 this.hasFocus = true;
38008 if(this.triggerAction == 'all') {
38009 this.doQuery(this.allQuery, true);
38011 this.doQuery(this.getRawValue());
38013 if (!this.blockFocus) {
38018 listKeyPress : function(e)
38020 //Roo.log('listkeypress');
38021 // scroll to first matching element based on key pres..
38022 if (e.isSpecialKey()) {
38025 var k = String.fromCharCode(e.getKey()).toUpperCase();
38028 var csel = this.view.getSelectedNodes();
38029 var cselitem = false;
38031 var ix = this.view.indexOf(csel[0]);
38032 cselitem = this.store.getAt(ix);
38033 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38039 this.store.each(function(v) {
38041 // start at existing selection.
38042 if (cselitem.id == v.id) {
38048 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38049 match = this.store.indexOf(v);
38054 if (match === false) {
38055 return true; // no more action?
38058 this.view.select(match);
38059 var sn = Roo.get(this.view.getSelectedNodes()[0])
38060 sn.scrollIntoView(sn.dom.parentNode, false);
38064 * @cfg {Boolean} grow
38068 * @cfg {Number} growMin
38072 * @cfg {Number} growMax
38081 * Ext JS Library 1.1.1
38082 * Copyright(c) 2006-2007, Ext JS, LLC.
38084 * Originally Released Under LGPL - original licence link has changed is not relivant.
38087 * <script type="text/javascript">
38090 * @class Roo.form.Checkbox
38091 * @extends Roo.form.Field
38092 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38094 * Creates a new Checkbox
38095 * @param {Object} config Configuration options
38097 Roo.form.Checkbox = function(config){
38098 Roo.form.Checkbox.superclass.constructor.call(this, config);
38102 * Fires when the checkbox is checked or unchecked.
38103 * @param {Roo.form.Checkbox} this This checkbox
38104 * @param {Boolean} checked The new checked value
38110 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38112 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38114 focusClass : undefined,
38116 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38118 fieldClass: "x-form-field",
38120 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38124 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38125 * {tag: "input", type: "checkbox", autocomplete: "off"})
38127 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38129 * @cfg {String} boxLabel The text that appears beside the checkbox
38133 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38137 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38139 valueOff: '0', // value when not checked..
38141 actionMode : 'viewEl',
38144 itemCls : 'x-menu-check-item x-form-item',
38145 groupClass : 'x-menu-group-item',
38146 inputType : 'hidden',
38149 inSetChecked: false, // check that we are not calling self...
38151 inputElement: false, // real input element?
38152 basedOn: false, // ????
38154 isFormField: true, // not sure where this is needed!!!!
38156 onResize : function(){
38157 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38158 if(!this.boxLabel){
38159 this.el.alignTo(this.wrap, 'c-c');
38163 initEvents : function(){
38164 Roo.form.Checkbox.superclass.initEvents.call(this);
38165 this.el.on("click", this.onClick, this);
38166 this.el.on("change", this.onClick, this);
38170 getResizeEl : function(){
38174 getPositionEl : function(){
38179 onRender : function(ct, position){
38180 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38182 if(this.inputValue !== undefined){
38183 this.el.dom.value = this.inputValue;
38186 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38187 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38188 var viewEl = this.wrap.createChild({
38189 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38190 this.viewEl = viewEl;
38191 this.wrap.on('click', this.onClick, this);
38193 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38194 this.el.on('propertychange', this.setFromHidden, this); //ie
38199 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38200 // viewEl.on('click', this.onClick, this);
38202 //if(this.checked){
38203 this.setChecked(this.checked);
38205 //this.checked = this.el.dom;
38211 initValue : Roo.emptyFn,
38214 * Returns the checked state of the checkbox.
38215 * @return {Boolean} True if checked, else false
38217 getValue : function(){
38219 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38221 return this.valueOff;
38226 onClick : function(){
38227 this.setChecked(!this.checked);
38229 //if(this.el.dom.checked != this.checked){
38230 // this.setValue(this.el.dom.checked);
38235 * Sets the checked state of the checkbox.
38236 * On is always based on a string comparison between inputValue and the param.
38237 * @param {Boolean/String} value - the value to set
38238 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38240 setValue : function(v,suppressEvent){
38243 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38244 //if(this.el && this.el.dom){
38245 // this.el.dom.checked = this.checked;
38246 // this.el.dom.defaultChecked = this.checked;
38248 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38249 //this.fireEvent("check", this, this.checked);
38252 setChecked : function(state,suppressEvent)
38254 if (this.inSetChecked) {
38255 this.checked = state;
38261 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38263 this.checked = state;
38264 if(suppressEvent !== true){
38265 this.fireEvent('check', this, state);
38267 this.inSetChecked = true;
38268 this.el.dom.value = state ? this.inputValue : this.valueOff;
38269 this.inSetChecked = false;
38272 // handle setting of hidden value by some other method!!?!?
38273 setFromHidden: function()
38278 //console.log("SET FROM HIDDEN");
38279 //alert('setFrom hidden');
38280 this.setValue(this.el.dom.value);
38283 onDestroy : function()
38286 Roo.get(this.viewEl).remove();
38289 Roo.form.Checkbox.superclass.onDestroy.call(this);
38294 * Ext JS Library 1.1.1
38295 * Copyright(c) 2006-2007, Ext JS, LLC.
38297 * Originally Released Under LGPL - original licence link has changed is not relivant.
38300 * <script type="text/javascript">
38304 * @class Roo.form.Radio
38305 * @extends Roo.form.Checkbox
38306 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38307 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38309 * Creates a new Radio
38310 * @param {Object} config Configuration options
38312 Roo.form.Radio = function(){
38313 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38315 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38316 inputType: 'radio',
38319 * If this radio is part of a group, it will return the selected value
38322 getGroupValue : function(){
38323 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38325 });//<script type="text/javascript">
38328 * Ext JS Library 1.1.1
38329 * Copyright(c) 2006-2007, Ext JS, LLC.
38330 * licensing@extjs.com
38332 * http://www.extjs.com/license
38338 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38339 * - IE ? - no idea how much works there.
38347 * @class Ext.form.HtmlEditor
38348 * @extends Ext.form.Field
38349 * Provides a lightweight HTML Editor component.
38350 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38352 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38353 * supported by this editor.</b><br/><br/>
38354 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38355 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38357 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38359 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38363 * @cfg {String} createLinkText The default text for the create link prompt
38365 createLinkText : 'Please enter the URL for the link:',
38367 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38369 defaultLinkValue : 'http:/'+'/',
38375 // private properties
38376 validationEvent : false,
38378 initialized : false,
38380 sourceEditMode : false,
38381 onFocus : Roo.emptyFn,
38383 hideMode:'offsets',
38384 defaultAutoCreate : {
38386 style:"width:500px;height:300px;",
38387 autocomplete: "off"
38391 initComponent : function(){
38394 * @event initialize
38395 * Fires when the editor is fully initialized (including the iframe)
38396 * @param {HtmlEditor} this
38401 * Fires when the editor is first receives the focus. Any insertion must wait
38402 * until after this event.
38403 * @param {HtmlEditor} this
38407 * @event beforesync
38408 * Fires before the textarea is updated with content from the editor iframe. Return false
38409 * to cancel the sync.
38410 * @param {HtmlEditor} this
38411 * @param {String} html
38415 * @event beforepush
38416 * Fires before the iframe editor is updated with content from the textarea. Return false
38417 * to cancel the push.
38418 * @param {HtmlEditor} this
38419 * @param {String} html
38424 * Fires when the textarea is updated with content from the editor iframe.
38425 * @param {HtmlEditor} this
38426 * @param {String} html
38431 * Fires when the iframe editor is updated with content from the textarea.
38432 * @param {HtmlEditor} this
38433 * @param {String} html
38437 * @event editmodechange
38438 * Fires when the editor switches edit modes
38439 * @param {HtmlEditor} this
38440 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38442 editmodechange: true,
38444 * @event editorevent
38445 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38446 * @param {HtmlEditor} this
38453 * Protected method that will not generally be called directly. It
38454 * is called when the editor creates its toolbar. Override this method if you need to
38455 * add custom toolbar buttons.
38456 * @param {HtmlEditor} editor
38458 createToolbar : function(editor){
38459 if (!editor.toolbars || !editor.toolbars.length) {
38460 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38463 for (var i =0 ; i < editor.toolbars.length;i++) {
38464 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38465 editor.toolbars[i].init(editor);
38472 * Protected method that will not generally be called directly. It
38473 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38474 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38476 getDocMarkup : function(){
38477 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38481 onRender : function(ct, position){
38482 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38483 this.el.dom.style.border = '0 none';
38484 this.el.dom.setAttribute('tabIndex', -1);
38485 this.el.addClass('x-hidden');
38486 if(Roo.isIE){ // fix IE 1px bogus margin
38487 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38489 this.wrap = this.el.wrap({
38490 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38493 this.frameId = Roo.id();
38494 this.createToolbar(this);
38501 var iframe = this.wrap.createChild({
38504 name: this.frameId,
38505 frameBorder : 'no',
38506 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38509 // console.log(iframe);
38510 //this.wrap.dom.appendChild(iframe);
38512 this.iframe = iframe.dom;
38514 this.assignDocWin();
38516 this.doc.designMode = 'on';
38519 this.doc.write(this.getDocMarkup());
38523 var task = { // must defer to wait for browser to be ready
38525 //console.log("run task?" + this.doc.readyState);
38526 this.assignDocWin();
38527 if(this.doc.body || this.doc.readyState == 'complete'){
38529 this.doc.designMode="on";
38533 Roo.TaskMgr.stop(task);
38534 this.initEditor.defer(10, this);
38541 Roo.TaskMgr.start(task);
38544 this.setSize(this.el.getSize());
38549 onResize : function(w, h){
38550 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38551 if(this.el && this.iframe){
38552 if(typeof w == 'number'){
38553 var aw = w - this.wrap.getFrameWidth('lr');
38554 this.el.setWidth(this.adjustWidth('textarea', aw));
38555 this.iframe.style.width = aw + 'px';
38557 if(typeof h == 'number'){
38559 for (var i =0; i < this.toolbars.length;i++) {
38560 // fixme - ask toolbars for heights?
38561 tbh += this.toolbars[i].tb.el.getHeight();
38567 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38568 this.el.setHeight(this.adjustWidth('textarea', ah));
38569 this.iframe.style.height = ah + 'px';
38571 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38578 * Toggles the editor between standard and source edit mode.
38579 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38581 toggleSourceEdit : function(sourceEditMode){
38583 this.sourceEditMode = sourceEditMode === true;
38585 if(this.sourceEditMode){
38588 this.iframe.className = 'x-hidden';
38589 this.el.removeClass('x-hidden');
38590 this.el.dom.removeAttribute('tabIndex');
38595 this.iframe.className = '';
38596 this.el.addClass('x-hidden');
38597 this.el.dom.setAttribute('tabIndex', -1);
38600 this.setSize(this.wrap.getSize());
38601 this.fireEvent('editmodechange', this, this.sourceEditMode);
38604 // private used internally
38605 createLink : function(){
38606 var url = prompt(this.createLinkText, this.defaultLinkValue);
38607 if(url && url != 'http:/'+'/'){
38608 this.relayCmd('createlink', url);
38612 // private (for BoxComponent)
38613 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38615 // private (for BoxComponent)
38616 getResizeEl : function(){
38620 // private (for BoxComponent)
38621 getPositionEl : function(){
38626 initEvents : function(){
38627 this.originalValue = this.getValue();
38631 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38634 markInvalid : Roo.emptyFn,
38636 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38639 clearInvalid : Roo.emptyFn,
38641 setValue : function(v){
38642 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38647 * Protected method that will not generally be called directly. If you need/want
38648 * custom HTML cleanup, this is the method you should override.
38649 * @param {String} html The HTML to be cleaned
38650 * return {String} The cleaned HTML
38652 cleanHtml : function(html){
38653 html = String(html);
38654 if(html.length > 5){
38655 if(Roo.isSafari){ // strip safari nonsense
38656 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38659 if(html == ' '){
38666 * Protected method that will not generally be called directly. Syncs the contents
38667 * of the editor iframe with the textarea.
38669 syncValue : function(){
38670 if(this.initialized){
38671 var bd = (this.doc.body || this.doc.documentElement);
38672 this.cleanUpPaste();
38673 var html = bd.innerHTML;
38675 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38676 var m = bs.match(/text-align:(.*?);/i);
38678 html = '<div style="'+m[0]+'">' + html + '</div>';
38681 html = this.cleanHtml(html);
38682 if(this.fireEvent('beforesync', this, html) !== false){
38683 this.el.dom.value = html;
38684 this.fireEvent('sync', this, html);
38690 * Protected method that will not generally be called directly. Pushes the value of the textarea
38691 * into the iframe editor.
38693 pushValue : function(){
38694 if(this.initialized){
38695 var v = this.el.dom.value;
38700 if(this.fireEvent('beforepush', this, v) !== false){
38701 var d = (this.doc.body || this.doc.documentElement);
38703 this.cleanUpPaste();
38704 this.el.dom.value = d.innerHTML;
38705 this.fireEvent('push', this, v);
38711 deferFocus : function(){
38712 this.focus.defer(10, this);
38716 focus : function(){
38717 if(this.win && !this.sourceEditMode){
38724 assignDocWin: function()
38726 var iframe = this.iframe;
38729 this.doc = iframe.contentWindow.document;
38730 this.win = iframe.contentWindow;
38732 if (!Roo.get(this.frameId)) {
38735 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38736 this.win = Roo.get(this.frameId).dom.contentWindow;
38741 initEditor : function(){
38742 //console.log("INIT EDITOR");
38743 this.assignDocWin();
38747 this.doc.designMode="on";
38749 this.doc.write(this.getDocMarkup());
38752 var dbody = (this.doc.body || this.doc.documentElement);
38753 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38754 // this copies styles from the containing element into thsi one..
38755 // not sure why we need all of this..
38756 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38757 ss['background-attachment'] = 'fixed'; // w3c
38758 dbody.bgProperties = 'fixed'; // ie
38759 Roo.DomHelper.applyStyles(dbody, ss);
38760 Roo.EventManager.on(this.doc, {
38761 'mousedown': this.onEditorEvent,
38762 'dblclick': this.onEditorEvent,
38763 'click': this.onEditorEvent,
38764 'keyup': this.onEditorEvent,
38769 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38771 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38772 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38774 this.initialized = true;
38776 this.fireEvent('initialize', this);
38781 onDestroy : function(){
38787 for (var i =0; i < this.toolbars.length;i++) {
38788 // fixme - ask toolbars for heights?
38789 this.toolbars[i].onDestroy();
38792 this.wrap.dom.innerHTML = '';
38793 this.wrap.remove();
38798 onFirstFocus : function(){
38800 this.assignDocWin();
38803 this.activated = true;
38804 for (var i =0; i < this.toolbars.length;i++) {
38805 this.toolbars[i].onFirstFocus();
38808 if(Roo.isGecko){ // prevent silly gecko errors
38810 var s = this.win.getSelection();
38811 if(!s.focusNode || s.focusNode.nodeType != 3){
38812 var r = s.getRangeAt(0);
38813 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38818 this.execCmd('useCSS', true);
38819 this.execCmd('styleWithCSS', false);
38822 this.fireEvent('activate', this);
38826 adjustFont: function(btn){
38827 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38828 //if(Roo.isSafari){ // safari
38831 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38832 if(Roo.isSafari){ // safari
38833 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38834 v = (v < 10) ? 10 : v;
38835 v = (v > 48) ? 48 : v;
38836 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38841 v = Math.max(1, v+adjust);
38843 this.execCmd('FontSize', v );
38846 onEditorEvent : function(e){
38847 this.fireEvent('editorevent', this, e);
38848 // this.updateToolbar();
38852 insertTag : function(tg)
38854 // could be a bit smarter... -> wrap the current selected tRoo..
38856 this.execCmd("formatblock", tg);
38860 insertText : function(txt)
38864 range = this.createRange();
38865 range.deleteContents();
38866 //alert(Sender.getAttribute('label'));
38868 range.insertNode(this.doc.createTextNode(txt));
38872 relayBtnCmd : function(btn){
38873 this.relayCmd(btn.cmd);
38877 * Executes a Midas editor command on the editor document and performs necessary focus and
38878 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38879 * @param {String} cmd The Midas command
38880 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38882 relayCmd : function(cmd, value){
38884 this.execCmd(cmd, value);
38885 this.fireEvent('editorevent', this);
38886 //this.updateToolbar();
38891 * Executes a Midas editor command directly on the editor document.
38892 * For visual commands, you should use {@link #relayCmd} instead.
38893 * <b>This should only be called after the editor is initialized.</b>
38894 * @param {String} cmd The Midas command
38895 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38897 execCmd : function(cmd, value){
38898 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38904 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38906 * @param {String} text
38908 insertAtCursor : function(text){
38909 if(!this.activated){
38914 var r = this.doc.selection.createRange();
38921 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38923 this.execCmd('InsertHTML', text);
38928 mozKeyPress : function(e){
38930 var c = e.getCharCode(), cmd;
38933 c = String.fromCharCode(c).toLowerCase();
38944 this.cleanUpPaste.defer(100, this);
38952 e.preventDefault();
38960 fixKeys : function(){ // load time branching for fastest keydown performance
38962 return function(e){
38963 var k = e.getKey(), r;
38966 r = this.doc.selection.createRange();
38969 r.pasteHTML('    ');
38976 r = this.doc.selection.createRange();
38978 var target = r.parentElement();
38979 if(!target || target.tagName.toLowerCase() != 'li'){
38981 r.pasteHTML('<br />');
38987 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38988 this.cleanUpPaste.defer(100, this);
38994 }else if(Roo.isOpera){
38995 return function(e){
38996 var k = e.getKey();
39000 this.execCmd('InsertHTML','    ');
39003 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39004 this.cleanUpPaste.defer(100, this);
39009 }else if(Roo.isSafari){
39010 return function(e){
39011 var k = e.getKey();
39015 this.execCmd('InsertText','\t');
39019 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39020 this.cleanUpPaste.defer(100, this);
39028 getAllAncestors: function()
39030 var p = this.getSelectedNode();
39033 a.push(p); // push blank onto stack..
39034 p = this.getParentElement();
39038 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39042 a.push(this.doc.body);
39046 lastSelNode : false,
39049 getSelection : function()
39051 this.assignDocWin();
39052 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39055 getSelectedNode: function()
39057 // this may only work on Gecko!!!
39059 // should we cache this!!!!
39064 var range = this.createRange(this.getSelection());
39067 var parent = range.parentElement();
39069 var testRange = range.duplicate();
39070 testRange.moveToElementText(parent);
39071 if (testRange.inRange(range)) {
39074 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39077 parent = parent.parentElement;
39083 var ar = range.endContainer.childNodes;
39085 ar = range.commonAncestorContainer.childNodes;
39086 //alert(ar.length);
39089 var other_nodes = [];
39090 var has_other_nodes = false;
39091 for (var i=0;i<ar.length;i++) {
39092 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39095 // fullly contained node.
39097 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39102 // probably selected..
39103 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39104 other_nodes.push(ar[i]);
39107 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39112 has_other_nodes = true;
39114 if (!nodes.length && other_nodes.length) {
39115 nodes= other_nodes;
39117 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39123 createRange: function(sel)
39125 // this has strange effects when using with
39126 // top toolbar - not sure if it's a great idea.
39127 //this.editor.contentWindow.focus();
39128 if (typeof sel != "undefined") {
39130 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39132 return this.doc.createRange();
39135 return this.doc.createRange();
39138 getParentElement: function()
39141 this.assignDocWin();
39142 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39144 var range = this.createRange(sel);
39147 var p = range.commonAncestorContainer;
39148 while (p.nodeType == 3) { // text node
39160 // BC Hacks - cause I cant work out what i was trying to do..
39161 rangeIntersectsNode : function(range, node)
39163 var nodeRange = node.ownerDocument.createRange();
39165 nodeRange.selectNode(node);
39168 nodeRange.selectNodeContents(node);
39171 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39172 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39174 rangeCompareNode : function(range, node) {
39175 var nodeRange = node.ownerDocument.createRange();
39177 nodeRange.selectNode(node);
39179 nodeRange.selectNodeContents(node);
39181 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39182 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39184 if (nodeIsBefore && !nodeIsAfter)
39186 if (!nodeIsBefore && nodeIsAfter)
39188 if (nodeIsBefore && nodeIsAfter)
39194 // private? - in a new class?
39195 cleanUpPaste : function()
39197 // cleans up the whole document..
39198 // console.log('cleanuppaste');
39199 this.cleanUpChildren(this.doc.body);
39203 cleanUpChildren : function (n)
39205 if (!n.childNodes.length) {
39208 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39209 this.cleanUpChild(n.childNodes[i]);
39216 cleanUpChild : function (node)
39218 //console.log(node);
39219 if (node.nodeName == "#text") {
39220 // clean up silly Windows -- stuff?
39223 if (node.nodeName == "#comment") {
39224 node.parentNode.removeChild(node);
39225 // clean up silly Windows -- stuff?
39229 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39231 node.parentNode.removeChild(node);
39235 if (!node.attributes || !node.attributes.length) {
39236 this.cleanUpChildren(node);
39240 function cleanAttr(n,v)
39243 if (v.match(/^\./) || v.match(/^\//)) {
39246 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39249 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39250 node.removeAttribute(n);
39254 function cleanStyle(n,v)
39256 if (v.match(/expression/)) { //XSS?? should we even bother..
39257 node.removeAttribute(n);
39262 var parts = v.split(/;/);
39263 Roo.each(parts, function(p) {
39264 p = p.replace(/\s+/g,'');
39268 var l = p.split(':').shift().replace(/\s+/g,'');
39270 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39271 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39272 node.removeAttribute(n);
39281 for (var i = node.attributes.length-1; i > -1 ; i--) {
39282 var a = node.attributes[i];
39284 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39285 node.removeAttribute(a.name);
39288 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39289 cleanAttr(a.name,a.value); // fixme..
39292 if (a.name == 'style') {
39293 cleanStyle(a.name,a.value);
39295 /// clean up MS crap..
39296 if (a.name == 'class') {
39297 if (a.value.match(/^Mso/)) {
39298 node.className = '';
39308 this.cleanUpChildren(node);
39314 // hide stuff that is not compatible
39328 * @event specialkey
39332 * @cfg {String} fieldClass @hide
39335 * @cfg {String} focusClass @hide
39338 * @cfg {String} autoCreate @hide
39341 * @cfg {String} inputType @hide
39344 * @cfg {String} invalidClass @hide
39347 * @cfg {String} invalidText @hide
39350 * @cfg {String} msgFx @hide
39353 * @cfg {String} validateOnBlur @hide
39357 Roo.form.HtmlEditor.white = [
39358 'area', 'br', 'img', 'input', 'hr', 'wbr',
39360 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39361 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39362 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39363 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39364 'table', 'ul', 'xmp',
39366 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39369 'dir', 'menu', 'ol', 'ul', 'dl',
39375 Roo.form.HtmlEditor.black = [
39376 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39378 'base', 'basefont', 'bgsound', 'blink', 'body',
39379 'frame', 'frameset', 'head', 'html', 'ilayer',
39380 'iframe', 'layer', 'link', 'meta', 'object',
39381 'script', 'style' ,'title', 'xml' // clean later..
39383 Roo.form.HtmlEditor.clean = [
39384 'script', 'style', 'title', 'xml'
39389 Roo.form.HtmlEditor.ablack = [
39393 Roo.form.HtmlEditor.aclean = [
39394 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39398 Roo.form.HtmlEditor.pwhite= [
39399 'http', 'https', 'mailto'
39402 Roo.form.HtmlEditor.cwhite= [
39407 // <script type="text/javascript">
39410 * Ext JS Library 1.1.1
39411 * Copyright(c) 2006-2007, Ext JS, LLC.
39417 * @class Roo.form.HtmlEditorToolbar1
39422 new Roo.form.HtmlEditor({
39425 new Roo.form.HtmlEditorToolbar1({
39426 disable : { fonts: 1 , format: 1, ..., ... , ...],
39432 * @cfg {Object} disable List of elements to disable..
39433 * @cfg {Array} btns List of additional buttons.
39437 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39440 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39443 Roo.apply(this, config);
39444 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39445 // dont call parent... till later.
39448 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39456 * @cfg {Object} disable List of toolbar elements to disable
39461 * @cfg {Array} fontFamilies An array of available font families
39479 // "á" , ?? a acute?
39484 "°" // , // degrees
39486 // "é" , // e ecute
39487 // "ú" , // u ecute?
39490 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39491 "input:submit", "input:button", "select", "textarea", "label" ],
39494 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39496 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39499 * @cfg {String} defaultFont default font to use.
39501 defaultFont: 'tahoma',
39503 fontSelect : false,
39506 formatCombo : false,
39508 init : function(editor)
39510 this.editor = editor;
39513 var fid = editor.frameId;
39515 function btn(id, toggle, handler){
39516 var xid = fid + '-'+ id ;
39520 cls : 'x-btn-icon x-edit-'+id,
39521 enableToggle:toggle !== false,
39522 scope: editor, // was editor...
39523 handler:handler||editor.relayBtnCmd,
39524 clickEvent:'mousedown',
39525 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39532 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39534 // stop form submits
39535 tb.el.on('click', function(e){
39536 e.preventDefault(); // what does this do?
39539 if(!this.disable.font && !Roo.isSafari){
39540 /* why no safari for fonts
39541 editor.fontSelect = tb.el.createChild({
39544 cls:'x-font-select',
39545 html: editor.createFontOptions()
39547 editor.fontSelect.on('change', function(){
39548 var font = editor.fontSelect.dom.value;
39549 editor.relayCmd('fontname', font);
39550 editor.deferFocus();
39553 editor.fontSelect.dom,
39558 if(!this.disable.formats){
39559 this.formatCombo = new Roo.form.ComboBox({
39560 store: new Roo.data.SimpleStore({
39563 data : this.formats // from states.js
39566 //autoCreate : {tag: "div", size: "20"},
39567 displayField:'tag',
39571 triggerAction: 'all',
39572 emptyText:'Add tag',
39573 selectOnFocus:true,
39576 'select': function(c, r, i) {
39577 editor.insertTag(r.get('tag'));
39583 tb.addField(this.formatCombo);
39587 if(!this.disable.format){
39594 if(!this.disable.fontSize){
39599 btn('increasefontsize', false, editor.adjustFont),
39600 btn('decreasefontsize', false, editor.adjustFont)
39605 if(this.disable.colors){
39608 id:editor.frameId +'-forecolor',
39609 cls:'x-btn-icon x-edit-forecolor',
39610 clickEvent:'mousedown',
39611 tooltip: this.buttonTips['forecolor'] || undefined,
39613 menu : new Roo.menu.ColorMenu({
39614 allowReselect: true,
39615 focus: Roo.emptyFn,
39618 selectHandler: function(cp, color){
39619 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39620 editor.deferFocus();
39623 clickEvent:'mousedown'
39626 id:editor.frameId +'backcolor',
39627 cls:'x-btn-icon x-edit-backcolor',
39628 clickEvent:'mousedown',
39629 tooltip: this.buttonTips['backcolor'] || undefined,
39631 menu : new Roo.menu.ColorMenu({
39632 focus: Roo.emptyFn,
39635 allowReselect: true,
39636 selectHandler: function(cp, color){
39638 editor.execCmd('useCSS', false);
39639 editor.execCmd('hilitecolor', color);
39640 editor.execCmd('useCSS', true);
39641 editor.deferFocus();
39643 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39644 Roo.isSafari || Roo.isIE ? '#'+color : color);
39645 editor.deferFocus();
39649 clickEvent:'mousedown'
39654 // now add all the items...
39657 if(!this.disable.alignments){
39660 btn('justifyleft'),
39661 btn('justifycenter'),
39662 btn('justifyright')
39666 //if(!Roo.isSafari){
39667 if(!this.disable.links){
39670 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39674 if(!this.disable.lists){
39677 btn('insertorderedlist'),
39678 btn('insertunorderedlist')
39681 if(!this.disable.sourceEdit){
39684 btn('sourceedit', true, function(btn){
39685 this.toggleSourceEdit(btn.pressed);
39692 // special menu.. - needs to be tidied up..
39693 if (!this.disable.special) {
39696 cls: 'x-edit-none',
39701 for (var i =0; i < this.specialChars.length; i++) {
39702 smenu.menu.items.push({
39704 html: this.specialChars[i],
39705 handler: function(a,b) {
39706 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39719 for(var i =0; i< this.btns.length;i++) {
39720 var b = this.btns[i];
39721 b.cls = 'x-edit-none';
39730 // disable everything...
39732 this.tb.items.each(function(item){
39733 if(item.id != editor.frameId+ '-sourceedit'){
39737 this.rendered = true;
39739 // the all the btns;
39740 editor.on('editorevent', this.updateToolbar, this);
39741 // other toolbars need to implement this..
39742 //editor.on('editmodechange', this.updateToolbar, this);
39748 * Protected method that will not generally be called directly. It triggers
39749 * a toolbar update by reading the markup state of the current selection in the editor.
39751 updateToolbar: function(){
39753 if(!this.editor.activated){
39754 this.editor.onFirstFocus();
39758 var btns = this.tb.items.map,
39759 doc = this.editor.doc,
39760 frameId = this.editor.frameId;
39762 if(!this.disable.font && !Roo.isSafari){
39764 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39765 if(name != this.fontSelect.dom.value){
39766 this.fontSelect.dom.value = name;
39770 if(!this.disable.format){
39771 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39772 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39773 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39775 if(!this.disable.alignments){
39776 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39777 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39778 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39780 if(!Roo.isSafari && !this.disable.lists){
39781 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39782 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39785 var ans = this.editor.getAllAncestors();
39786 if (this.formatCombo) {
39789 var store = this.formatCombo.store;
39790 this.formatCombo.setValue("");
39791 for (var i =0; i < ans.length;i++) {
39792 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39794 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39802 // hides menus... - so this cant be on a menu...
39803 Roo.menu.MenuMgr.hideAll();
39805 //this.editorsyncValue();
39809 createFontOptions : function(){
39810 var buf = [], fs = this.fontFamilies, ff, lc;
39811 for(var i = 0, len = fs.length; i< len; i++){
39813 lc = ff.toLowerCase();
39815 '<option value="',lc,'" style="font-family:',ff,';"',
39816 (this.defaultFont == lc ? ' selected="true">' : '>'),
39821 return buf.join('');
39824 toggleSourceEdit : function(sourceEditMode){
39825 if(sourceEditMode === undefined){
39826 sourceEditMode = !this.sourceEditMode;
39828 this.sourceEditMode = sourceEditMode === true;
39829 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39830 // just toggle the button?
39831 if(btn.pressed !== this.editor.sourceEditMode){
39832 btn.toggle(this.editor.sourceEditMode);
39836 if(this.sourceEditMode){
39837 this.tb.items.each(function(item){
39838 if(item.cmd != 'sourceedit'){
39844 if(this.initialized){
39845 this.tb.items.each(function(item){
39851 // tell the editor that it's been pressed..
39852 this.editor.toggleSourceEdit(sourceEditMode);
39856 * Object collection of toolbar tooltips for the buttons in the editor. The key
39857 * is the command id associated with that button and the value is a valid QuickTips object.
39862 title: 'Bold (Ctrl+B)',
39863 text: 'Make the selected text bold.',
39864 cls: 'x-html-editor-tip'
39867 title: 'Italic (Ctrl+I)',
39868 text: 'Make the selected text italic.',
39869 cls: 'x-html-editor-tip'
39877 title: 'Bold (Ctrl+B)',
39878 text: 'Make the selected text bold.',
39879 cls: 'x-html-editor-tip'
39882 title: 'Italic (Ctrl+I)',
39883 text: 'Make the selected text italic.',
39884 cls: 'x-html-editor-tip'
39887 title: 'Underline (Ctrl+U)',
39888 text: 'Underline the selected text.',
39889 cls: 'x-html-editor-tip'
39891 increasefontsize : {
39892 title: 'Grow Text',
39893 text: 'Increase the font size.',
39894 cls: 'x-html-editor-tip'
39896 decreasefontsize : {
39897 title: 'Shrink Text',
39898 text: 'Decrease the font size.',
39899 cls: 'x-html-editor-tip'
39902 title: 'Text Highlight Color',
39903 text: 'Change the background color of the selected text.',
39904 cls: 'x-html-editor-tip'
39907 title: 'Font Color',
39908 text: 'Change the color of the selected text.',
39909 cls: 'x-html-editor-tip'
39912 title: 'Align Text Left',
39913 text: 'Align text to the left.',
39914 cls: 'x-html-editor-tip'
39917 title: 'Center Text',
39918 text: 'Center text in the editor.',
39919 cls: 'x-html-editor-tip'
39922 title: 'Align Text Right',
39923 text: 'Align text to the right.',
39924 cls: 'x-html-editor-tip'
39926 insertunorderedlist : {
39927 title: 'Bullet List',
39928 text: 'Start a bulleted list.',
39929 cls: 'x-html-editor-tip'
39931 insertorderedlist : {
39932 title: 'Numbered List',
39933 text: 'Start a numbered list.',
39934 cls: 'x-html-editor-tip'
39937 title: 'Hyperlink',
39938 text: 'Make the selected text a hyperlink.',
39939 cls: 'x-html-editor-tip'
39942 title: 'Source Edit',
39943 text: 'Switch to source editing mode.',
39944 cls: 'x-html-editor-tip'
39948 onDestroy : function(){
39951 this.tb.items.each(function(item){
39953 item.menu.removeAll();
39955 item.menu.el.destroy();
39963 onFirstFocus: function() {
39964 this.tb.items.each(function(item){
39973 // <script type="text/javascript">
39976 * Ext JS Library 1.1.1
39977 * Copyright(c) 2006-2007, Ext JS, LLC.
39984 * @class Roo.form.HtmlEditor.ToolbarContext
39989 new Roo.form.HtmlEditor({
39992 new Roo.form.HtmlEditor.ToolbarStandard(),
39993 new Roo.form.HtmlEditor.ToolbarContext()
39998 * @config : {Object} disable List of elements to disable.. (not done yet.)
40003 Roo.form.HtmlEditor.ToolbarContext = function(config)
40006 Roo.apply(this, config);
40007 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40008 // dont call parent... till later.
40010 Roo.form.HtmlEditor.ToolbarContext.types = {
40022 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40084 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40089 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40153 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40161 * @cfg {Object} disable List of toolbar elements to disable
40170 init : function(editor)
40172 this.editor = editor;
40175 var fid = editor.frameId;
40177 function btn(id, toggle, handler){
40178 var xid = fid + '-'+ id ;
40182 cls : 'x-btn-icon x-edit-'+id,
40183 enableToggle:toggle !== false,
40184 scope: editor, // was editor...
40185 handler:handler||editor.relayBtnCmd,
40186 clickEvent:'mousedown',
40187 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40191 // create a new element.
40192 var wdiv = editor.wrap.createChild({
40194 }, editor.wrap.dom.firstChild.nextSibling, true);
40196 // can we do this more than once??
40198 // stop form submits
40201 // disable everything...
40202 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40203 this.toolbars = {};
40205 for (var i in ty) {
40207 this.toolbars[i] = this.buildToolbar(ty[i],i);
40209 this.tb = this.toolbars.BODY;
40213 this.rendered = true;
40215 // the all the btns;
40216 editor.on('editorevent', this.updateToolbar, this);
40217 // other toolbars need to implement this..
40218 //editor.on('editmodechange', this.updateToolbar, this);
40224 * Protected method that will not generally be called directly. It triggers
40225 * a toolbar update by reading the markup state of the current selection in the editor.
40227 updateToolbar: function(){
40229 if(!this.editor.activated){
40230 this.editor.onFirstFocus();
40235 var ans = this.editor.getAllAncestors();
40238 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40239 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40240 sel = sel ? sel : this.editor.doc.body;
40241 sel = sel.tagName.length ? sel : this.editor.doc.body;
40242 var tn = sel.tagName.toUpperCase();
40243 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40244 tn = sel.tagName.toUpperCase();
40245 if (this.tb.name == tn) {
40246 return; // no change
40249 ///console.log("show: " + tn);
40250 this.tb = this.toolbars[tn];
40252 this.tb.fields.each(function(e) {
40253 e.setValue(sel.getAttribute(e.name));
40255 this.tb.selectedNode = sel;
40258 Roo.menu.MenuMgr.hideAll();
40260 //this.editorsyncValue();
40265 onDestroy : function(){
40268 this.tb.items.each(function(item){
40270 item.menu.removeAll();
40272 item.menu.el.destroy();
40280 onFirstFocus: function() {
40281 // need to do this for all the toolbars..
40282 this.tb.items.each(function(item){
40286 buildToolbar: function(tlist, nm)
40288 var editor = this.editor;
40289 // create a new element.
40290 var wdiv = editor.wrap.createChild({
40292 }, editor.wrap.dom.firstChild.nextSibling, true);
40295 var tb = new Roo.Toolbar(wdiv);
40296 tb.add(nm+ ": ");
40297 for (var i in tlist) {
40298 var item = tlist[i];
40299 tb.add(item.title + ": ");
40304 tb.addField( new Roo.form.ComboBox({
40305 store: new Roo.data.SimpleStore({
40308 data : item.opts // from states.js
40311 displayField:'val',
40315 triggerAction: 'all',
40316 emptyText:'Select',
40317 selectOnFocus:true,
40318 width: item.width ? item.width : 130,
40320 'select': function(c, r, i) {
40321 tb.selectedNode.setAttribute(c.name, r.get('val'));
40332 tb.addField( new Roo.form.TextField({
40335 //allowBlank:false,
40340 tb.addField( new Roo.form.TextField({
40346 'change' : function(f, nv, ov) {
40347 tb.selectedNode.setAttribute(f.name, nv);
40353 tb.el.on('click', function(e){
40354 e.preventDefault(); // what does this do?
40356 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40359 // dont need to disable them... as they will get hidden
40376 * Ext JS Library 1.1.1
40377 * Copyright(c) 2006-2007, Ext JS, LLC.
40379 * Originally Released Under LGPL - original licence link has changed is not relivant.
40382 * <script type="text/javascript">
40386 * @class Roo.form.BasicForm
40387 * @extends Roo.util.Observable
40388 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40390 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40391 * @param {Object} config Configuration options
40393 Roo.form.BasicForm = function(el, config){
40394 this.allItems = [];
40395 this.childForms = [];
40396 Roo.apply(this, config);
40398 * The Roo.form.Field items in this form.
40399 * @type MixedCollection
40403 this.items = new Roo.util.MixedCollection(false, function(o){
40404 return o.id || (o.id = Roo.id());
40408 * @event beforeaction
40409 * Fires before any action is performed. Return false to cancel the action.
40410 * @param {Form} this
40411 * @param {Action} action The action to be performed
40413 beforeaction: true,
40415 * @event actionfailed
40416 * Fires when an action fails.
40417 * @param {Form} this
40418 * @param {Action} action The action that failed
40420 actionfailed : true,
40422 * @event actioncomplete
40423 * Fires when an action is completed.
40424 * @param {Form} this
40425 * @param {Action} action The action that completed
40427 actioncomplete : true
40432 Roo.form.BasicForm.superclass.constructor.call(this);
40435 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40437 * @cfg {String} method
40438 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40441 * @cfg {DataReader} reader
40442 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40443 * This is optional as there is built-in support for processing JSON.
40446 * @cfg {DataReader} errorReader
40447 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40448 * This is completely optional as there is built-in support for processing JSON.
40451 * @cfg {String} url
40452 * The URL to use for form actions if one isn't supplied in the action options.
40455 * @cfg {Boolean} fileUpload
40456 * Set to true if this form is a file upload.
40460 * @cfg {Object} baseParams
40461 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40466 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40471 activeAction : null,
40474 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40475 * or setValues() data instead of when the form was first created.
40477 trackResetOnLoad : false,
40481 * childForms - used for multi-tab forms
40484 childForms : false,
40487 * allItems - full list of fields.
40493 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40494 * element by passing it or its id or mask the form itself by passing in true.
40497 waitMsgTarget : false,
40500 initEl : function(el){
40501 this.el = Roo.get(el);
40502 this.id = this.el.id || Roo.id();
40503 this.el.on('submit', this.onSubmit, this);
40504 this.el.addClass('x-form');
40508 onSubmit : function(e){
40513 * Returns true if client-side validation on the form is successful.
40516 isValid : function(){
40518 this.items.each(function(f){
40527 * Returns true if any fields in this form have changed since their original load.
40530 isDirty : function(){
40532 this.items.each(function(f){
40542 * Performs a predefined action (submit or load) or custom actions you define on this form.
40543 * @param {String} actionName The name of the action type
40544 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40545 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40546 * accept other config options):
40548 Property Type Description
40549 ---------------- --------------- ----------------------------------------------------------------------------------
40550 url String The url for the action (defaults to the form's url)
40551 method String The form method to use (defaults to the form's method, or POST if not defined)
40552 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40553 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40554 validate the form on the client (defaults to false)
40556 * @return {BasicForm} this
40558 doAction : function(action, options){
40559 if(typeof action == 'string'){
40560 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40562 if(this.fireEvent('beforeaction', this, action) !== false){
40563 this.beforeAction(action);
40564 action.run.defer(100, action);
40570 * Shortcut to do a submit action.
40571 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40572 * @return {BasicForm} this
40574 submit : function(options){
40575 this.doAction('submit', options);
40580 * Shortcut to do a load action.
40581 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40582 * @return {BasicForm} this
40584 load : function(options){
40585 this.doAction('load', options);
40590 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40591 * @param {Record} record The record to edit
40592 * @return {BasicForm} this
40594 updateRecord : function(record){
40595 record.beginEdit();
40596 var fs = record.fields;
40597 fs.each(function(f){
40598 var field = this.findField(f.name);
40600 record.set(f.name, field.getValue());
40608 * Loads an Roo.data.Record into this form.
40609 * @param {Record} record The record to load
40610 * @return {BasicForm} this
40612 loadRecord : function(record){
40613 this.setValues(record.data);
40618 beforeAction : function(action){
40619 var o = action.options;
40622 if(this.waitMsgTarget === true){
40623 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40624 }else if(this.waitMsgTarget){
40625 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40626 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40628 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40634 afterAction : function(action, success){
40635 this.activeAction = null;
40636 var o = action.options;
40638 if(this.waitMsgTarget === true){
40640 }else if(this.waitMsgTarget){
40641 this.waitMsgTarget.unmask();
40643 Roo.MessageBox.updateProgress(1);
40644 Roo.MessageBox.hide();
40651 Roo.callback(o.success, o.scope, [this, action]);
40652 this.fireEvent('actioncomplete', this, action);
40655 Roo.callback(o.failure, o.scope, [this, action]);
40656 // show an error message if no failed handler is set..
40657 if (!this.hasListener('actionfailed')) {
40658 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40661 this.fireEvent('actionfailed', this, action);
40667 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40668 * @param {String} id The value to search for
40671 findField : function(id){
40672 var field = this.items.get(id);
40674 this.items.each(function(f){
40675 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40681 return field || null;
40685 * Add a secondary form to this one,
40686 * Used to provide tabbed forms. One form is primary, with hidden values
40687 * which mirror the elements from the other forms.
40689 * @param {Roo.form.Form} form to add.
40692 addForm : function(form)
40695 if (this.childForms.indexOf(form) > -1) {
40699 this.childForms.push(form);
40701 Roo.each(form.allItems, function (fe) {
40703 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40704 if (this.findField(n)) { // already added..
40707 var add = new Roo.form.Hidden({
40710 add.render(this.el);
40717 * Mark fields in this form invalid in bulk.
40718 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40719 * @return {BasicForm} this
40721 markInvalid : function(errors){
40722 if(errors instanceof Array){
40723 for(var i = 0, len = errors.length; i < len; i++){
40724 var fieldError = errors[i];
40725 var f = this.findField(fieldError.id);
40727 f.markInvalid(fieldError.msg);
40733 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40734 field.markInvalid(errors[id]);
40738 Roo.each(this.childForms || [], function (f) {
40739 f.markInvalid(errors);
40746 * Set values for fields in this form in bulk.
40747 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40748 * @return {BasicForm} this
40750 setValues : function(values){
40751 if(values instanceof Array){ // array of objects
40752 for(var i = 0, len = values.length; i < len; i++){
40754 var f = this.findField(v.id);
40756 f.setValue(v.value);
40757 if(this.trackResetOnLoad){
40758 f.originalValue = f.getValue();
40762 }else{ // object hash
40765 if(typeof values[id] != 'function' && (field = this.findField(id))){
40767 if (field.setFromData &&
40768 field.valueField &&
40769 field.displayField &&
40770 // combos' with local stores can
40771 // be queried via setValue()
40772 // to set their value..
40773 (field.store && !field.store.isLocal)
40777 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40778 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40779 field.setFromData(sd);
40782 field.setValue(values[id]);
40786 if(this.trackResetOnLoad){
40787 field.originalValue = field.getValue();
40793 Roo.each(this.childForms || [], function (f) {
40794 f.setValues(values);
40801 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40802 * they are returned as an array.
40803 * @param {Boolean} asString
40806 getValues : function(asString){
40807 if (this.childForms) {
40808 // copy values from the child forms
40809 Roo.each(this.childForms, function (f) {
40810 this.setValues(f.getValues());
40816 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40817 if(asString === true){
40820 return Roo.urlDecode(fs);
40824 * Returns the fields in this form as an object with key/value pairs.
40825 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40828 getFieldValues : function()
40830 if (this.childForms) {
40831 // copy values from the child forms
40832 Roo.each(this.childForms, function (f) {
40833 this.setValues(f.getValues());
40838 this.items.each(function(f){
40839 if (!f.getName()) {
40842 var v = f.getValue();
40843 if ((typeof(v) == 'object') && f.getRawValue) {
40844 v = f.getRawValue() ; // dates..
40846 ret[f.getName()] = v;
40853 * Clears all invalid messages in this form.
40854 * @return {BasicForm} this
40856 clearInvalid : function(){
40857 this.items.each(function(f){
40861 Roo.each(this.childForms || [], function (f) {
40870 * Resets this form.
40871 * @return {BasicForm} this
40873 reset : function(){
40874 this.items.each(function(f){
40878 Roo.each(this.childForms || [], function (f) {
40887 * Add Roo.form components to this form.
40888 * @param {Field} field1
40889 * @param {Field} field2 (optional)
40890 * @param {Field} etc (optional)
40891 * @return {BasicForm} this
40894 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40900 * Removes a field from the items collection (does NOT remove its markup).
40901 * @param {Field} field
40902 * @return {BasicForm} this
40904 remove : function(field){
40905 this.items.remove(field);
40910 * Looks at the fields in this form, checks them for an id attribute,
40911 * and calls applyTo on the existing dom element with that id.
40912 * @return {BasicForm} this
40914 render : function(){
40915 this.items.each(function(f){
40916 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40924 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40925 * @param {Object} values
40926 * @return {BasicForm} this
40928 applyToFields : function(o){
40929 this.items.each(function(f){
40936 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40937 * @param {Object} values
40938 * @return {BasicForm} this
40940 applyIfToFields : function(o){
40941 this.items.each(function(f){
40949 Roo.BasicForm = Roo.form.BasicForm;/*
40951 * Ext JS Library 1.1.1
40952 * Copyright(c) 2006-2007, Ext JS, LLC.
40954 * Originally Released Under LGPL - original licence link has changed is not relivant.
40957 * <script type="text/javascript">
40961 * @class Roo.form.Form
40962 * @extends Roo.form.BasicForm
40963 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40965 * @param {Object} config Configuration options
40967 Roo.form.Form = function(config){
40969 if (config.items) {
40970 xitems = config.items;
40971 delete config.items;
40975 Roo.form.Form.superclass.constructor.call(this, null, config);
40976 this.url = this.url || this.action;
40978 this.root = new Roo.form.Layout(Roo.applyIf({
40982 this.active = this.root;
40984 * Array of all the buttons that have been added to this form via {@link addButton}
40988 this.allItems = [];
40991 * @event clientvalidation
40992 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40993 * @param {Form} this
40994 * @param {Boolean} valid true if the form has passed client-side validation
40996 clientvalidation: true,
40999 * Fires when the form is rendered
41000 * @param {Roo.form.Form} form
41005 if (this.progressUrl) {
41006 // push a hidden field onto the list of fields..
41010 name : 'UPLOAD_IDENTIFIER'
41015 Roo.each(xitems, this.addxtype, this);
41021 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41023 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41026 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41029 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41031 buttonAlign:'center',
41034 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41039 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41040 * This property cascades to child containers if not set.
41045 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41046 * fires a looping event with that state. This is required to bind buttons to the valid
41047 * state using the config value formBind:true on the button.
41049 monitorValid : false,
41052 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41057 * @cfg {String} progressUrl - Url to return progress data
41060 progressUrl : false,
41063 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41064 * fields are added and the column is closed. If no fields are passed the column remains open
41065 * until end() is called.
41066 * @param {Object} config The config to pass to the column
41067 * @param {Field} field1 (optional)
41068 * @param {Field} field2 (optional)
41069 * @param {Field} etc (optional)
41070 * @return Column The column container object
41072 column : function(c){
41073 var col = new Roo.form.Column(c);
41075 if(arguments.length > 1){ // duplicate code required because of Opera
41076 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41083 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41084 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41085 * until end() is called.
41086 * @param {Object} config The config to pass to the fieldset
41087 * @param {Field} field1 (optional)
41088 * @param {Field} field2 (optional)
41089 * @param {Field} etc (optional)
41090 * @return FieldSet The fieldset container object
41092 fieldset : function(c){
41093 var fs = new Roo.form.FieldSet(c);
41095 if(arguments.length > 1){ // duplicate code required because of Opera
41096 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41103 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41104 * fields are added and the container is closed. If no fields are passed the container remains open
41105 * until end() is called.
41106 * @param {Object} config The config to pass to the Layout
41107 * @param {Field} field1 (optional)
41108 * @param {Field} field2 (optional)
41109 * @param {Field} etc (optional)
41110 * @return Layout The container object
41112 container : function(c){
41113 var l = new Roo.form.Layout(c);
41115 if(arguments.length > 1){ // duplicate code required because of Opera
41116 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41123 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41124 * @param {Object} container A Roo.form.Layout or subclass of Layout
41125 * @return {Form} this
41127 start : function(c){
41128 // cascade label info
41129 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41130 this.active.stack.push(c);
41131 c.ownerCt = this.active;
41137 * Closes the current open container
41138 * @return {Form} this
41141 if(this.active == this.root){
41144 this.active = this.active.ownerCt;
41149 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41150 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41151 * as the label of the field.
41152 * @param {Field} field1
41153 * @param {Field} field2 (optional)
41154 * @param {Field} etc. (optional)
41155 * @return {Form} this
41158 this.active.stack.push.apply(this.active.stack, arguments);
41159 this.allItems.push.apply(this.allItems,arguments);
41161 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41162 if(a[i].isFormField){
41167 Roo.form.Form.superclass.add.apply(this, r);
41177 * Find any element that has been added to a form, using it's ID or name
41178 * This can include framesets, columns etc. along with regular fields..
41179 * @param {String} id - id or name to find.
41181 * @return {Element} e - or false if nothing found.
41183 findbyId : function(id)
41189 Roo.each(this.allItems, function(f){
41190 if (f.id == id || f.name == id ){
41201 * Render this form into the passed container. This should only be called once!
41202 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41203 * @return {Form} this
41205 render : function(ct)
41211 var o = this.autoCreate || {
41213 method : this.method || 'POST',
41214 id : this.id || Roo.id()
41216 this.initEl(ct.createChild(o));
41218 this.root.render(this.el);
41222 this.items.each(function(f){
41223 f.render('x-form-el-'+f.id);
41226 if(this.buttons.length > 0){
41227 // tables are required to maintain order and for correct IE layout
41228 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41229 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41230 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41232 var tr = tb.getElementsByTagName('tr')[0];
41233 for(var i = 0, len = this.buttons.length; i < len; i++) {
41234 var b = this.buttons[i];
41235 var td = document.createElement('td');
41236 td.className = 'x-form-btn-td';
41237 b.render(tr.appendChild(td));
41240 if(this.monitorValid){ // initialize after render
41241 this.startMonitoring();
41243 this.fireEvent('rendered', this);
41248 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41249 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41250 * object or a valid Roo.DomHelper element config
41251 * @param {Function} handler The function called when the button is clicked
41252 * @param {Object} scope (optional) The scope of the handler function
41253 * @return {Roo.Button}
41255 addButton : function(config, handler, scope){
41259 minWidth: this.minButtonWidth,
41262 if(typeof config == "string"){
41265 Roo.apply(bc, config);
41267 var btn = new Roo.Button(null, bc);
41268 this.buttons.push(btn);
41273 * Adds a series of form elements (using the xtype property as the factory method.
41274 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41275 * @param {Object} config
41278 addxtype : function()
41280 var ar = Array.prototype.slice.call(arguments, 0);
41282 for(var i = 0; i < ar.length; i++) {
41284 continue; // skip -- if this happends something invalid got sent, we
41285 // should ignore it, as basically that interface element will not show up
41286 // and that should be pretty obvious!!
41289 if (Roo.form[ar[i].xtype]) {
41291 var fe = Roo.factory(ar[i], Roo.form);
41297 fe.store.form = this;
41302 this.allItems.push(fe);
41303 if (fe.items && fe.addxtype) {
41304 fe.addxtype.apply(fe, fe.items);
41314 // console.log('adding ' + ar[i].xtype);
41316 if (ar[i].xtype == 'Button') {
41317 //console.log('adding button');
41318 //console.log(ar[i]);
41319 this.addButton(ar[i]);
41320 this.allItems.push(fe);
41324 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41325 alert('end is not supported on xtype any more, use items');
41327 // //console.log('adding end');
41335 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41336 * option "monitorValid"
41338 startMonitoring : function(){
41341 Roo.TaskMgr.start({
41342 run : this.bindHandler,
41343 interval : this.monitorPoll || 200,
41350 * Stops monitoring of the valid state of this form
41352 stopMonitoring : function(){
41353 this.bound = false;
41357 bindHandler : function(){
41359 return false; // stops binding
41362 this.items.each(function(f){
41363 if(!f.isValid(true)){
41368 for(var i = 0, len = this.buttons.length; i < len; i++){
41369 var btn = this.buttons[i];
41370 if(btn.formBind === true && btn.disabled === valid){
41371 btn.setDisabled(!valid);
41374 this.fireEvent('clientvalidation', this, valid);
41388 Roo.Form = Roo.form.Form;
41391 * Ext JS Library 1.1.1
41392 * Copyright(c) 2006-2007, Ext JS, LLC.
41394 * Originally Released Under LGPL - original licence link has changed is not relivant.
41397 * <script type="text/javascript">
41401 * @class Roo.form.Action
41402 * Internal Class used to handle form actions
41404 * @param {Roo.form.BasicForm} el The form element or its id
41405 * @param {Object} config Configuration options
41409 // define the action interface
41410 Roo.form.Action = function(form, options){
41412 this.options = options || {};
41415 * Client Validation Failed
41418 Roo.form.Action.CLIENT_INVALID = 'client';
41420 * Server Validation Failed
41423 Roo.form.Action.SERVER_INVALID = 'server';
41425 * Connect to Server Failed
41428 Roo.form.Action.CONNECT_FAILURE = 'connect';
41430 * Reading Data from Server Failed
41433 Roo.form.Action.LOAD_FAILURE = 'load';
41435 Roo.form.Action.prototype = {
41437 failureType : undefined,
41438 response : undefined,
41439 result : undefined,
41441 // interface method
41442 run : function(options){
41446 // interface method
41447 success : function(response){
41451 // interface method
41452 handleResponse : function(response){
41456 // default connection failure
41457 failure : function(response){
41459 this.response = response;
41460 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41461 this.form.afterAction(this, false);
41464 processResponse : function(response){
41465 this.response = response;
41466 if(!response.responseText){
41469 this.result = this.handleResponse(response);
41470 return this.result;
41473 // utility functions used internally
41474 getUrl : function(appendParams){
41475 var url = this.options.url || this.form.url || this.form.el.dom.action;
41477 var p = this.getParams();
41479 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41485 getMethod : function(){
41486 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41489 getParams : function(){
41490 var bp = this.form.baseParams;
41491 var p = this.options.params;
41493 if(typeof p == "object"){
41494 p = Roo.urlEncode(Roo.applyIf(p, bp));
41495 }else if(typeof p == 'string' && bp){
41496 p += '&' + Roo.urlEncode(bp);
41499 p = Roo.urlEncode(bp);
41504 createCallback : function(){
41506 success: this.success,
41507 failure: this.failure,
41509 timeout: (this.form.timeout*1000),
41510 upload: this.form.fileUpload ? this.success : undefined
41515 Roo.form.Action.Submit = function(form, options){
41516 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41519 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41522 haveProgress : false,
41523 uploadComplete : false,
41525 // uploadProgress indicator.
41526 uploadProgress : function()
41528 if (!this.form.progressUrl) {
41532 if (!this.haveProgress) {
41533 Roo.MessageBox.progress("Uploading", "Uploading");
41535 if (this.uploadComplete) {
41536 Roo.MessageBox.hide();
41540 this.haveProgress = true;
41542 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41544 var c = new Roo.data.Connection();
41546 url : this.form.progressUrl,
41551 success : function(req){
41552 //console.log(data);
41556 rdata = Roo.decode(req.responseText)
41558 Roo.log("Invalid data from server..");
41562 if (!rdata || !rdata.success) {
41566 var data = rdata.data;
41568 if (this.uploadComplete) {
41569 Roo.MessageBox.hide();
41574 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41575 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41578 this.uploadProgress.defer(2000,this);
41581 failure: function(data) {
41582 Roo.log('progress url failed ');
41593 // run get Values on the form, so it syncs any secondary forms.
41594 this.form.getValues();
41596 var o = this.options;
41597 var method = this.getMethod();
41598 var isPost = method == 'POST';
41599 if(o.clientValidation === false || this.form.isValid()){
41601 if (this.form.progressUrl) {
41602 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41603 (new Date() * 1) + '' + Math.random());
41608 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41609 form:this.form.el.dom,
41610 url:this.getUrl(!isPost),
41612 params:isPost ? this.getParams() : null,
41613 isUpload: this.form.fileUpload
41616 this.uploadProgress();
41618 }else if (o.clientValidation !== false){ // client validation failed
41619 this.failureType = Roo.form.Action.CLIENT_INVALID;
41620 this.form.afterAction(this, false);
41624 success : function(response)
41626 this.uploadComplete= true;
41627 if (this.haveProgress) {
41628 Roo.MessageBox.hide();
41632 var result = this.processResponse(response);
41633 if(result === true || result.success){
41634 this.form.afterAction(this, true);
41638 this.form.markInvalid(result.errors);
41639 this.failureType = Roo.form.Action.SERVER_INVALID;
41641 this.form.afterAction(this, false);
41643 failure : function(response)
41645 this.uploadComplete= true;
41646 if (this.haveProgress) {
41647 Roo.MessageBox.hide();
41651 this.response = response;
41652 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41653 this.form.afterAction(this, false);
41656 handleResponse : function(response){
41657 if(this.form.errorReader){
41658 var rs = this.form.errorReader.read(response);
41661 for(var i = 0, len = rs.records.length; i < len; i++) {
41662 var r = rs.records[i];
41663 errors[i] = r.data;
41666 if(errors.length < 1){
41670 success : rs.success,
41676 ret = Roo.decode(response.responseText);
41680 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41690 Roo.form.Action.Load = function(form, options){
41691 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41692 this.reader = this.form.reader;
41695 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41700 Roo.Ajax.request(Roo.apply(
41701 this.createCallback(), {
41702 method:this.getMethod(),
41703 url:this.getUrl(false),
41704 params:this.getParams()
41708 success : function(response){
41710 var result = this.processResponse(response);
41711 if(result === true || !result.success || !result.data){
41712 this.failureType = Roo.form.Action.LOAD_FAILURE;
41713 this.form.afterAction(this, false);
41716 this.form.clearInvalid();
41717 this.form.setValues(result.data);
41718 this.form.afterAction(this, true);
41721 handleResponse : function(response){
41722 if(this.form.reader){
41723 var rs = this.form.reader.read(response);
41724 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41726 success : rs.success,
41730 return Roo.decode(response.responseText);
41734 Roo.form.Action.ACTION_TYPES = {
41735 'load' : Roo.form.Action.Load,
41736 'submit' : Roo.form.Action.Submit
41739 * Ext JS Library 1.1.1
41740 * Copyright(c) 2006-2007, Ext JS, LLC.
41742 * Originally Released Under LGPL - original licence link has changed is not relivant.
41745 * <script type="text/javascript">
41749 * @class Roo.form.Layout
41750 * @extends Roo.Component
41751 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41753 * @param {Object} config Configuration options
41755 Roo.form.Layout = function(config){
41757 if (config.items) {
41758 xitems = config.items;
41759 delete config.items;
41761 Roo.form.Layout.superclass.constructor.call(this, config);
41763 Roo.each(xitems, this.addxtype, this);
41767 Roo.extend(Roo.form.Layout, Roo.Component, {
41769 * @cfg {String/Object} autoCreate
41770 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41773 * @cfg {String/Object/Function} style
41774 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41775 * a function which returns such a specification.
41778 * @cfg {String} labelAlign
41779 * Valid values are "left," "top" and "right" (defaults to "left")
41782 * @cfg {Number} labelWidth
41783 * Fixed width in pixels of all field labels (defaults to undefined)
41786 * @cfg {Boolean} clear
41787 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41791 * @cfg {String} labelSeparator
41792 * The separator to use after field labels (defaults to ':')
41794 labelSeparator : ':',
41796 * @cfg {Boolean} hideLabels
41797 * True to suppress the display of field labels in this layout (defaults to false)
41799 hideLabels : false,
41802 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41807 onRender : function(ct, position){
41808 if(this.el){ // from markup
41809 this.el = Roo.get(this.el);
41810 }else { // generate
41811 var cfg = this.getAutoCreate();
41812 this.el = ct.createChild(cfg, position);
41815 this.el.applyStyles(this.style);
41817 if(this.labelAlign){
41818 this.el.addClass('x-form-label-'+this.labelAlign);
41820 if(this.hideLabels){
41821 this.labelStyle = "display:none";
41822 this.elementStyle = "padding-left:0;";
41824 if(typeof this.labelWidth == 'number'){
41825 this.labelStyle = "width:"+this.labelWidth+"px;";
41826 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41828 if(this.labelAlign == 'top'){
41829 this.labelStyle = "width:auto;";
41830 this.elementStyle = "padding-left:0;";
41833 var stack = this.stack;
41834 var slen = stack.length;
41836 if(!this.fieldTpl){
41837 var t = new Roo.Template(
41838 '<div class="x-form-item {5}">',
41839 '<label for="{0}" style="{2}">{1}{4}</label>',
41840 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41842 '</div><div class="x-form-clear-left"></div>'
41844 t.disableFormats = true;
41846 Roo.form.Layout.prototype.fieldTpl = t;
41848 for(var i = 0; i < slen; i++) {
41849 if(stack[i].isFormField){
41850 this.renderField(stack[i]);
41852 this.renderComponent(stack[i]);
41857 this.el.createChild({cls:'x-form-clear'});
41862 renderField : function(f){
41863 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41866 f.labelStyle||this.labelStyle||'', //2
41867 this.elementStyle||'', //3
41868 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41869 f.itemCls||this.itemCls||'' //5
41870 ], true).getPrevSibling());
41874 renderComponent : function(c){
41875 c.render(c.isLayout ? this.el : this.el.createChild());
41878 * Adds a object form elements (using the xtype property as the factory method.)
41879 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41880 * @param {Object} config
41882 addxtype : function(o)
41884 // create the lement.
41885 o.form = this.form;
41886 var fe = Roo.factory(o, Roo.form);
41887 this.form.allItems.push(fe);
41888 this.stack.push(fe);
41890 if (fe.isFormField) {
41891 this.form.items.add(fe);
41899 * @class Roo.form.Column
41900 * @extends Roo.form.Layout
41901 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41903 * @param {Object} config Configuration options
41905 Roo.form.Column = function(config){
41906 Roo.form.Column.superclass.constructor.call(this, config);
41909 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41911 * @cfg {Number/String} width
41912 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41915 * @cfg {String/Object} autoCreate
41916 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41920 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41923 onRender : function(ct, position){
41924 Roo.form.Column.superclass.onRender.call(this, ct, position);
41926 this.el.setWidth(this.width);
41933 * @class Roo.form.Row
41934 * @extends Roo.form.Layout
41935 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41937 * @param {Object} config Configuration options
41941 Roo.form.Row = function(config){
41942 Roo.form.Row.superclass.constructor.call(this, config);
41945 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41947 * @cfg {Number/String} width
41948 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41951 * @cfg {Number/String} height
41952 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41954 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41958 onRender : function(ct, position){
41959 //console.log('row render');
41961 var t = new Roo.Template(
41962 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41963 '<label for="{0}" style="{2}">{1}{4}</label>',
41964 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41968 t.disableFormats = true;
41970 Roo.form.Layout.prototype.rowTpl = t;
41972 this.fieldTpl = this.rowTpl;
41974 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41975 var labelWidth = 100;
41977 if ((this.labelAlign != 'top')) {
41978 if (typeof this.labelWidth == 'number') {
41979 labelWidth = this.labelWidth
41981 this.padWidth = 20 + labelWidth;
41985 Roo.form.Column.superclass.onRender.call(this, ct, position);
41987 this.el.setWidth(this.width);
41990 this.el.setHeight(this.height);
41995 renderField : function(f){
41996 f.fieldEl = this.fieldTpl.append(this.el, [
41997 f.id, f.fieldLabel,
41998 f.labelStyle||this.labelStyle||'',
41999 this.elementStyle||'',
42000 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42001 f.itemCls||this.itemCls||'',
42002 f.width ? f.width + this.padWidth : 160 + this.padWidth
42009 * @class Roo.form.FieldSet
42010 * @extends Roo.form.Layout
42011 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42013 * @param {Object} config Configuration options
42015 Roo.form.FieldSet = function(config){
42016 Roo.form.FieldSet.superclass.constructor.call(this, config);
42019 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42021 * @cfg {String} legend
42022 * The text to display as the legend for the FieldSet (defaults to '')
42025 * @cfg {String/Object} autoCreate
42026 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42030 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42033 onRender : function(ct, position){
42034 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42036 this.setLegend(this.legend);
42041 setLegend : function(text){
42043 this.el.child('legend').update(text);
42048 * Ext JS Library 1.1.1
42049 * Copyright(c) 2006-2007, Ext JS, LLC.
42051 * Originally Released Under LGPL - original licence link has changed is not relivant.
42054 * <script type="text/javascript">
42057 * @class Roo.form.VTypes
42058 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42061 Roo.form.VTypes = function(){
42062 // closure these in so they are only created once.
42063 var alpha = /^[a-zA-Z_]+$/;
42064 var alphanum = /^[a-zA-Z0-9_]+$/;
42065 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42066 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42068 // All these messages and functions are configurable
42071 * The function used to validate email addresses
42072 * @param {String} value The email address
42074 'email' : function(v){
42075 return email.test(v);
42078 * The error text to display when the email validation function returns false
42081 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42083 * The keystroke filter mask to be applied on email input
42086 'emailMask' : /[a-z0-9_\.\-@]/i,
42089 * The function used to validate URLs
42090 * @param {String} value The URL
42092 'url' : function(v){
42093 return url.test(v);
42096 * The error text to display when the url validation function returns false
42099 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42102 * The function used to validate alpha values
42103 * @param {String} value The value
42105 'alpha' : function(v){
42106 return alpha.test(v);
42109 * The error text to display when the alpha validation function returns false
42112 'alphaText' : 'This field should only contain letters and _',
42114 * The keystroke filter mask to be applied on alpha input
42117 'alphaMask' : /[a-z_]/i,
42120 * The function used to validate alphanumeric values
42121 * @param {String} value The value
42123 'alphanum' : function(v){
42124 return alphanum.test(v);
42127 * The error text to display when the alphanumeric validation function returns false
42130 'alphanumText' : 'This field should only contain letters, numbers and _',
42132 * The keystroke filter mask to be applied on alphanumeric input
42135 'alphanumMask' : /[a-z0-9_]/i
42137 }();//<script type="text/javascript">
42140 * @class Roo.form.FCKeditor
42141 * @extends Roo.form.TextArea
42142 * Wrapper around the FCKEditor http://www.fckeditor.net
42144 * Creates a new FCKeditor
42145 * @param {Object} config Configuration options
42147 Roo.form.FCKeditor = function(config){
42148 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42151 * @event editorinit
42152 * Fired when the editor is initialized - you can add extra handlers here..
42153 * @param {FCKeditor} this
42154 * @param {Object} the FCK object.
42161 Roo.form.FCKeditor.editors = { };
42162 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42164 //defaultAutoCreate : {
42165 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42169 * @cfg {Object} fck options - see fck manual for details.
42174 * @cfg {Object} fck toolbar set (Basic or Default)
42176 toolbarSet : 'Basic',
42178 * @cfg {Object} fck BasePath
42180 basePath : '/fckeditor/',
42188 onRender : function(ct, position)
42191 this.defaultAutoCreate = {
42193 style:"width:300px;height:60px;",
42194 autocomplete: "off"
42197 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42200 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42201 if(this.preventScrollbars){
42202 this.el.setStyle("overflow", "hidden");
42204 this.el.setHeight(this.growMin);
42207 //console.log('onrender' + this.getId() );
42208 Roo.form.FCKeditor.editors[this.getId()] = this;
42211 this.replaceTextarea() ;
42215 getEditor : function() {
42216 return this.fckEditor;
42219 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42220 * @param {Mixed} value The value to set
42224 setValue : function(value)
42226 //console.log('setValue: ' + value);
42228 if(typeof(value) == 'undefined') { // not sure why this is happending...
42231 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42233 //if(!this.el || !this.getEditor()) {
42234 // this.value = value;
42235 //this.setValue.defer(100,this,[value]);
42239 if(!this.getEditor()) {
42243 this.getEditor().SetData(value);
42250 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42251 * @return {Mixed} value The field value
42253 getValue : function()
42256 if (this.frame && this.frame.dom.style.display == 'none') {
42257 return Roo.form.FCKeditor.superclass.getValue.call(this);
42260 if(!this.el || !this.getEditor()) {
42262 // this.getValue.defer(100,this);
42267 var value=this.getEditor().GetData();
42268 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42269 return Roo.form.FCKeditor.superclass.getValue.call(this);
42275 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42276 * @return {Mixed} value The field value
42278 getRawValue : function()
42280 if (this.frame && this.frame.dom.style.display == 'none') {
42281 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42284 if(!this.el || !this.getEditor()) {
42285 //this.getRawValue.defer(100,this);
42292 var value=this.getEditor().GetData();
42293 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42294 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42298 setSize : function(w,h) {
42302 //if (this.frame && this.frame.dom.style.display == 'none') {
42303 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42306 //if(!this.el || !this.getEditor()) {
42307 // this.setSize.defer(100,this, [w,h]);
42313 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42315 this.frame.dom.setAttribute('width', w);
42316 this.frame.dom.setAttribute('height', h);
42317 this.frame.setSize(w,h);
42321 toggleSourceEdit : function(value) {
42325 this.el.dom.style.display = value ? '' : 'none';
42326 this.frame.dom.style.display = value ? 'none' : '';
42331 focus: function(tag)
42333 if (this.frame.dom.style.display == 'none') {
42334 return Roo.form.FCKeditor.superclass.focus.call(this);
42336 if(!this.el || !this.getEditor()) {
42337 this.focus.defer(100,this, [tag]);
42344 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42345 this.getEditor().Focus();
42347 if (!this.getEditor().Selection.GetSelection()) {
42348 this.focus.defer(100,this, [tag]);
42353 var r = this.getEditor().EditorDocument.createRange();
42354 r.setStart(tgs[0],0);
42355 r.setEnd(tgs[0],0);
42356 this.getEditor().Selection.GetSelection().removeAllRanges();
42357 this.getEditor().Selection.GetSelection().addRange(r);
42358 this.getEditor().Focus();
42365 replaceTextarea : function()
42367 if ( document.getElementById( this.getId() + '___Frame' ) )
42369 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42371 // We must check the elements firstly using the Id and then the name.
42372 var oTextarea = document.getElementById( this.getId() );
42374 var colElementsByName = document.getElementsByName( this.getId() ) ;
42376 oTextarea.style.display = 'none' ;
42378 if ( oTextarea.tabIndex ) {
42379 this.TabIndex = oTextarea.tabIndex ;
42382 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42383 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42384 this.frame = Roo.get(this.getId() + '___Frame')
42387 _getConfigHtml : function()
42391 for ( var o in this.fckconfig ) {
42392 sConfig += sConfig.length > 0 ? '&' : '';
42393 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42396 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42400 _getIFrameHtml : function()
42402 var sFile = 'fckeditor.html' ;
42403 /* no idea what this is about..
42406 if ( (/fcksource=true/i).test( window.top.location.search ) )
42407 sFile = 'fckeditor.original.html' ;
42412 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42413 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42416 var html = '<iframe id="' + this.getId() +
42417 '___Frame" src="' + sLink +
42418 '" width="' + this.width +
42419 '" height="' + this.height + '"' +
42420 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42421 ' frameborder="0" scrolling="no"></iframe>' ;
42426 _insertHtmlBefore : function( html, element )
42428 if ( element.insertAdjacentHTML ) {
42430 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42432 var oRange = document.createRange() ;
42433 oRange.setStartBefore( element ) ;
42434 var oFragment = oRange.createContextualFragment( html );
42435 element.parentNode.insertBefore( oFragment, element ) ;
42448 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42450 function FCKeditor_OnComplete(editorInstance){
42451 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42452 f.fckEditor = editorInstance;
42453 //console.log("loaded");
42454 f.fireEvent('editorinit', f, editorInstance);
42474 //<script type="text/javascript">
42476 * @class Roo.form.GridField
42477 * @extends Roo.form.Field
42478 * Embed a grid (or editable grid into a form)
42481 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42483 * xgrid.store = Roo.data.Store
42484 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42485 * xgrid.store.reader = Roo.data.JsonReader
42489 * Creates a new GridField
42490 * @param {Object} config Configuration options
42492 Roo.form.GridField = function(config){
42493 Roo.form.GridField.superclass.constructor.call(this, config);
42497 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42499 * @cfg {Number} width - used to restrict width of grid..
42503 * @cfg {Number} height - used to restrict height of grid..
42507 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42513 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42514 * {tag: "input", type: "checkbox", autocomplete: "off"})
42516 // defaultAutoCreate : { tag: 'div' },
42517 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42519 * @cfg {String} addTitle Text to include for adding a title.
42523 onResize : function(){
42524 Roo.form.Field.superclass.onResize.apply(this, arguments);
42527 initEvents : function(){
42528 // Roo.form.Checkbox.superclass.initEvents.call(this);
42529 // has no events...
42534 getResizeEl : function(){
42538 getPositionEl : function(){
42543 onRender : function(ct, position){
42545 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42546 var style = this.style;
42549 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42550 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42551 this.viewEl = this.wrap.createChild({ tag: 'div' });
42553 this.viewEl.applyStyles(style);
42556 this.viewEl.setWidth(this.width);
42559 this.viewEl.setHeight(this.height);
42561 //if(this.inputValue !== undefined){
42562 //this.setValue(this.value);
42565 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42568 this.grid.render();
42569 this.grid.getDataSource().on('remove', this.refreshValue, this);
42570 this.grid.getDataSource().on('update', this.refreshValue, this);
42571 this.grid.on('afteredit', this.refreshValue, this);
42577 * Sets the value of the item.
42578 * @param {String} either an object or a string..
42580 setValue : function(v){
42582 v = v || []; // empty set..
42583 // this does not seem smart - it really only affects memoryproxy grids..
42584 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42585 var ds = this.grid.getDataSource();
42586 // assumes a json reader..
42588 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42589 ds.loadData( data);
42591 Roo.form.GridField.superclass.setValue.call(this, v);
42592 this.refreshValue();
42593 // should load data in the grid really....
42597 refreshValue: function() {
42599 this.grid.getDataSource().each(function(r) {
42602 this.el.dom.value = Roo.encode(val);
42610 * Ext JS Library 1.1.1
42611 * Copyright(c) 2006-2007, Ext JS, LLC.
42613 * Originally Released Under LGPL - original licence link has changed is not relivant.
42616 * <script type="text/javascript">
42619 * @class Roo.form.DisplayField
42620 * @extends Roo.form.Field
42621 * A generic Field to display non-editable data.
42623 * Creates a new Display Field item.
42624 * @param {Object} config Configuration options
42626 Roo.form.DisplayField = function(config){
42627 Roo.form.DisplayField.superclass.constructor.call(this, config);
42631 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42632 inputType: 'hidden',
42638 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42640 focusClass : undefined,
42642 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42644 fieldClass: 'x-form-field',
42647 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42649 valueRenderer: undefined,
42653 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42654 * {tag: "input", type: "checkbox", autocomplete: "off"})
42657 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42659 onResize : function(){
42660 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42664 initEvents : function(){
42665 // Roo.form.Checkbox.superclass.initEvents.call(this);
42666 // has no events...
42671 getResizeEl : function(){
42675 getPositionEl : function(){
42680 onRender : function(ct, position){
42682 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42683 //if(this.inputValue !== undefined){
42684 this.wrap = this.el.wrap();
42686 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
42688 if (this.bodyStyle) {
42689 this.viewEl.applyStyles(this.bodyStyle);
42691 //this.viewEl.setStyle('padding', '2px');
42693 this.setValue(this.value);
42698 initValue : Roo.emptyFn,
42703 onClick : function(){
42708 * Sets the checked state of the checkbox.
42709 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42711 setValue : function(v){
42713 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42714 // this might be called before we have a dom element..
42715 if (!this.viewEl) {
42718 this.viewEl.dom.innerHTML = html;
42719 Roo.form.DisplayField.superclass.setValue.call(this, v);
42729 * @class Roo.form.DayPicker
42730 * @extends Roo.form.Field
42731 * A Day picker show [M] [T] [W] ....
42733 * Creates a new Day Picker
42734 * @param {Object} config Configuration options
42736 Roo.form.DayPicker= function(config){
42737 Roo.form.DayPicker.superclass.constructor.call(this, config);
42741 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
42743 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42745 focusClass : undefined,
42747 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42749 fieldClass: "x-form-field",
42752 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42753 * {tag: "input", type: "checkbox", autocomplete: "off"})
42755 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42758 actionMode : 'viewEl',
42762 inputType : 'hidden',
42765 inputElement: false, // real input element?
42766 basedOn: false, // ????
42768 isFormField: true, // not sure where this is needed!!!!
42770 onResize : function(){
42771 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42772 if(!this.boxLabel){
42773 this.el.alignTo(this.wrap, 'c-c');
42777 initEvents : function(){
42778 Roo.form.Checkbox.superclass.initEvents.call(this);
42779 this.el.on("click", this.onClick, this);
42780 this.el.on("change", this.onClick, this);
42784 getResizeEl : function(){
42788 getPositionEl : function(){
42794 onRender : function(ct, position){
42795 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42797 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
42799 var r1 = '<table><tr>';
42800 var r2 = '<tr class="x-form-daypick-icons">';
42801 for (var i=0; i < 7; i++) {
42802 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
42803 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
42806 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
42807 viewEl.select('img').on('click', this.onClick, this);
42808 this.viewEl = viewEl;
42811 // this will not work on Chrome!!!
42812 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42813 this.el.on('propertychange', this.setFromHidden, this); //ie
42821 initValue : Roo.emptyFn,
42824 * Returns the checked state of the checkbox.
42825 * @return {Boolean} True if checked, else false
42827 getValue : function(){
42828 return this.el.dom.value;
42833 onClick : function(e){
42834 //this.setChecked(!this.checked);
42835 Roo.get(e.target).toggleClass('x-menu-item-checked');
42836 this.refreshValue();
42837 //if(this.el.dom.checked != this.checked){
42838 // this.setValue(this.el.dom.checked);
42843 refreshValue : function()
42846 this.viewEl.select('img',true).each(function(e,i,n) {
42847 val += e.is(".x-menu-item-checked") ? String(n) : '';
42849 this.setValue(val, true);
42853 * Sets the checked state of the checkbox.
42854 * On is always based on a string comparison between inputValue and the param.
42855 * @param {Boolean/String} value - the value to set
42856 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42858 setValue : function(v,suppressEvent){
42859 if (!this.el.dom) {
42862 var old = this.el.dom.value ;
42863 this.el.dom.value = v;
42864 if (suppressEvent) {
42868 // update display..
42869 this.viewEl.select('img',true).each(function(e,i,n) {
42871 var on = e.is(".x-menu-item-checked");
42872 var newv = v.indexOf(String(n)) > -1;
42874 e.toggleClass('x-menu-item-checked');
42880 this.fireEvent('change', this, v, old);
42885 // handle setting of hidden value by some other method!!?!?
42886 setFromHidden: function()
42891 //console.log("SET FROM HIDDEN");
42892 //alert('setFrom hidden');
42893 this.setValue(this.el.dom.value);
42896 onDestroy : function()
42899 Roo.get(this.viewEl).remove();
42902 Roo.form.DayPicker.superclass.onDestroy.call(this);
42905 });//<script type="text/javasscript">
42909 * @class Roo.DDView
42910 * A DnD enabled version of Roo.View.
42911 * @param {Element/String} container The Element in which to create the View.
42912 * @param {String} tpl The template string used to create the markup for each element of the View
42913 * @param {Object} config The configuration properties. These include all the config options of
42914 * {@link Roo.View} plus some specific to this class.<br>
42916 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42917 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42919 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42920 .x-view-drag-insert-above {
42921 border-top:1px dotted #3366cc;
42923 .x-view-drag-insert-below {
42924 border-bottom:1px dotted #3366cc;
42930 Roo.DDView = function(container, tpl, config) {
42931 Roo.DDView.superclass.constructor.apply(this, arguments);
42932 this.getEl().setStyle("outline", "0px none");
42933 this.getEl().unselectable();
42934 if (this.dragGroup) {
42935 this.setDraggable(this.dragGroup.split(","));
42937 if (this.dropGroup) {
42938 this.setDroppable(this.dropGroup.split(","));
42940 if (this.deletable) {
42941 this.setDeletable();
42943 this.isDirtyFlag = false;
42949 Roo.extend(Roo.DDView, Roo.View, {
42950 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42951 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42952 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42953 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42957 reset: Roo.emptyFn,
42959 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42961 validate: function() {
42965 destroy: function() {
42966 this.purgeListeners();
42967 this.getEl.removeAllListeners();
42968 this.getEl().remove();
42969 if (this.dragZone) {
42970 if (this.dragZone.destroy) {
42971 this.dragZone.destroy();
42974 if (this.dropZone) {
42975 if (this.dropZone.destroy) {
42976 this.dropZone.destroy();
42981 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42982 getName: function() {
42986 /** Loads the View from a JSON string representing the Records to put into the Store. */
42987 setValue: function(v) {
42989 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42992 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42993 this.store.proxy = new Roo.data.MemoryProxy(data);
42997 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42998 getValue: function() {
43000 this.store.each(function(rec) {
43001 result += rec.id + ',';
43003 return result.substr(0, result.length - 1) + ')';
43006 getIds: function() {
43007 var i = 0, result = new Array(this.store.getCount());
43008 this.store.each(function(rec) {
43009 result[i++] = rec.id;
43014 isDirty: function() {
43015 return this.isDirtyFlag;
43019 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43020 * whole Element becomes the target, and this causes the drop gesture to append.
43022 getTargetFromEvent : function(e) {
43023 var target = e.getTarget();
43024 while ((target !== null) && (target.parentNode != this.el.dom)) {
43025 target = target.parentNode;
43028 target = this.el.dom.lastChild || this.el.dom;
43034 * Create the drag data which consists of an object which has the property "ddel" as
43035 * the drag proxy element.
43037 getDragData : function(e) {
43038 var target = this.findItemFromChild(e.getTarget());
43040 this.handleSelection(e);
43041 var selNodes = this.getSelectedNodes();
43044 copy: this.copy || (this.allowCopy && e.ctrlKey),
43048 var selectedIndices = this.getSelectedIndexes();
43049 for (var i = 0; i < selectedIndices.length; i++) {
43050 dragData.records.push(this.store.getAt(selectedIndices[i]));
43052 if (selNodes.length == 1) {
43053 dragData.ddel = target.cloneNode(true); // the div element
43055 var div = document.createElement('div'); // create the multi element drag "ghost"
43056 div.className = 'multi-proxy';
43057 for (var i = 0, len = selNodes.length; i < len; i++) {
43058 div.appendChild(selNodes[i].cloneNode(true));
43060 dragData.ddel = div;
43062 //console.log(dragData)
43063 //console.log(dragData.ddel.innerHTML)
43066 //console.log('nodragData')
43070 /** Specify to which ddGroup items in this DDView may be dragged. */
43071 setDraggable: function(ddGroup) {
43072 if (ddGroup instanceof Array) {
43073 Roo.each(ddGroup, this.setDraggable, this);
43076 if (this.dragZone) {
43077 this.dragZone.addToGroup(ddGroup);
43079 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43080 containerScroll: true,
43084 // Draggability implies selection. DragZone's mousedown selects the element.
43085 if (!this.multiSelect) { this.singleSelect = true; }
43087 // Wire the DragZone's handlers up to methods in *this*
43088 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43092 /** Specify from which ddGroup this DDView accepts drops. */
43093 setDroppable: function(ddGroup) {
43094 if (ddGroup instanceof Array) {
43095 Roo.each(ddGroup, this.setDroppable, this);
43098 if (this.dropZone) {
43099 this.dropZone.addToGroup(ddGroup);
43101 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
43102 containerScroll: true,
43106 // Wire the DropZone's handlers up to methods in *this*
43107 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
43108 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
43109 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
43110 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
43111 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
43115 /** Decide whether to drop above or below a View node. */
43116 getDropPoint : function(e, n, dd){
43117 if (n == this.el.dom) { return "above"; }
43118 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
43119 var c = t + (b - t) / 2;
43120 var y = Roo.lib.Event.getPageY(e);
43128 onNodeEnter : function(n, dd, e, data){
43132 onNodeOver : function(n, dd, e, data){
43133 var pt = this.getDropPoint(e, n, dd);
43134 // set the insert point style on the target node
43135 var dragElClass = this.dropNotAllowed;
43138 if (pt == "above"){
43139 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
43140 targetElClass = "x-view-drag-insert-above";
43142 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
43143 targetElClass = "x-view-drag-insert-below";
43145 if (this.lastInsertClass != targetElClass){
43146 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
43147 this.lastInsertClass = targetElClass;
43150 return dragElClass;
43153 onNodeOut : function(n, dd, e, data){
43154 this.removeDropIndicators(n);
43157 onNodeDrop : function(n, dd, e, data){
43158 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
43161 var pt = this.getDropPoint(e, n, dd);
43162 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
43163 if (pt == "below") { insertAt++; }
43164 for (var i = 0; i < data.records.length; i++) {
43165 var r = data.records[i];
43166 var dup = this.store.getById(r.id);
43167 if (dup && (dd != this.dragZone)) {
43168 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
43171 this.store.insert(insertAt++, r.copy());
43173 data.source.isDirtyFlag = true;
43175 this.store.insert(insertAt++, r);
43177 this.isDirtyFlag = true;
43180 this.dragZone.cachedTarget = null;
43184 removeDropIndicators : function(n){
43186 Roo.fly(n).removeClass([
43187 "x-view-drag-insert-above",
43188 "x-view-drag-insert-below"]);
43189 this.lastInsertClass = "_noclass";
43194 * Utility method. Add a delete option to the DDView's context menu.
43195 * @param {String} imageUrl The URL of the "delete" icon image.
43197 setDeletable: function(imageUrl) {
43198 if (!this.singleSelect && !this.multiSelect) {
43199 this.singleSelect = true;
43201 var c = this.getContextMenu();
43202 this.contextMenu.on("itemclick", function(item) {
43205 this.remove(this.getSelectedIndexes());
43209 this.contextMenu.add({
43216 /** Return the context menu for this DDView. */
43217 getContextMenu: function() {
43218 if (!this.contextMenu) {
43219 // Create the View's context menu
43220 this.contextMenu = new Roo.menu.Menu({
43221 id: this.id + "-contextmenu"
43223 this.el.on("contextmenu", this.showContextMenu, this);
43225 return this.contextMenu;
43228 disableContextMenu: function() {
43229 if (this.contextMenu) {
43230 this.el.un("contextmenu", this.showContextMenu, this);
43234 showContextMenu: function(e, item) {
43235 item = this.findItemFromChild(e.getTarget());
43238 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
43239 this.contextMenu.showAt(e.getXY());
43244 * Remove {@link Roo.data.Record}s at the specified indices.
43245 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
43247 remove: function(selectedIndices) {
43248 selectedIndices = [].concat(selectedIndices);
43249 for (var i = 0; i < selectedIndices.length; i++) {
43250 var rec = this.store.getAt(selectedIndices[i]);
43251 this.store.remove(rec);
43256 * Double click fires the event, but also, if this is draggable, and there is only one other
43257 * related DropZone, it transfers the selected node.
43259 onDblClick : function(e){
43260 var item = this.findItemFromChild(e.getTarget());
43262 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43265 if (this.dragGroup) {
43266 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43267 while (targets.indexOf(this.dropZone) > -1) {
43268 targets.remove(this.dropZone);
43270 if (targets.length == 1) {
43271 this.dragZone.cachedTarget = null;
43272 var el = Roo.get(targets[0].getEl());
43273 var box = el.getBox(true);
43274 targets[0].onNodeDrop(el.dom, {
43276 xy: [box.x, box.y + box.height - 1]
43277 }, null, this.getDragData(e));
43283 handleSelection: function(e) {
43284 this.dragZone.cachedTarget = null;
43285 var item = this.findItemFromChild(e.getTarget());
43287 this.clearSelections(true);
43290 if (item && (this.multiSelect || this.singleSelect)){
43291 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43292 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43293 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43294 this.unselect(item);
43296 this.select(item, this.multiSelect && e.ctrlKey);
43297 this.lastSelection = item;
43302 onItemClick : function(item, index, e){
43303 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43309 unselect : function(nodeInfo, suppressEvent){
43310 var node = this.getNode(nodeInfo);
43311 if(node && this.isSelected(node)){
43312 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43313 Roo.fly(node).removeClass(this.selectedClass);
43314 this.selections.remove(node);
43315 if(!suppressEvent){
43316 this.fireEvent("selectionchange", this, this.selections);
43324 * Ext JS Library 1.1.1
43325 * Copyright(c) 2006-2007, Ext JS, LLC.
43327 * Originally Released Under LGPL - original licence link has changed is not relivant.
43330 * <script type="text/javascript">
43334 * @class Roo.LayoutManager
43335 * @extends Roo.util.Observable
43336 * Base class for layout managers.
43338 Roo.LayoutManager = function(container, config){
43339 Roo.LayoutManager.superclass.constructor.call(this);
43340 this.el = Roo.get(container);
43341 // ie scrollbar fix
43342 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43343 document.body.scroll = "no";
43344 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43345 this.el.position('relative');
43347 this.id = this.el.id;
43348 this.el.addClass("x-layout-container");
43349 /** false to disable window resize monitoring @type Boolean */
43350 this.monitorWindowResize = true;
43355 * Fires when a layout is performed.
43356 * @param {Roo.LayoutManager} this
43360 * @event regionresized
43361 * Fires when the user resizes a region.
43362 * @param {Roo.LayoutRegion} region The resized region
43363 * @param {Number} newSize The new size (width for east/west, height for north/south)
43365 "regionresized" : true,
43367 * @event regioncollapsed
43368 * Fires when a region is collapsed.
43369 * @param {Roo.LayoutRegion} region The collapsed region
43371 "regioncollapsed" : true,
43373 * @event regionexpanded
43374 * Fires when a region is expanded.
43375 * @param {Roo.LayoutRegion} region The expanded region
43377 "regionexpanded" : true
43379 this.updating = false;
43380 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43383 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43385 * Returns true if this layout is currently being updated
43386 * @return {Boolean}
43388 isUpdating : function(){
43389 return this.updating;
43393 * Suspend the LayoutManager from doing auto-layouts while
43394 * making multiple add or remove calls
43396 beginUpdate : function(){
43397 this.updating = true;
43401 * Restore auto-layouts and optionally disable the manager from performing a layout
43402 * @param {Boolean} noLayout true to disable a layout update
43404 endUpdate : function(noLayout){
43405 this.updating = false;
43411 layout: function(){
43415 onRegionResized : function(region, newSize){
43416 this.fireEvent("regionresized", region, newSize);
43420 onRegionCollapsed : function(region){
43421 this.fireEvent("regioncollapsed", region);
43424 onRegionExpanded : function(region){
43425 this.fireEvent("regionexpanded", region);
43429 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43430 * performs box-model adjustments.
43431 * @return {Object} The size as an object {width: (the width), height: (the height)}
43433 getViewSize : function(){
43435 if(this.el.dom != document.body){
43436 size = this.el.getSize();
43438 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43440 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43441 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43446 * Returns the Element this layout is bound to.
43447 * @return {Roo.Element}
43449 getEl : function(){
43454 * Returns the specified region.
43455 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43456 * @return {Roo.LayoutRegion}
43458 getRegion : function(target){
43459 return this.regions[target.toLowerCase()];
43462 onWindowResize : function(){
43463 if(this.monitorWindowResize){
43469 * Ext JS Library 1.1.1
43470 * Copyright(c) 2006-2007, Ext JS, LLC.
43472 * Originally Released Under LGPL - original licence link has changed is not relivant.
43475 * <script type="text/javascript">
43478 * @class Roo.BorderLayout
43479 * @extends Roo.LayoutManager
43480 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43481 * please see: <br><br>
43482 * <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>
43483 * <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>
43486 var layout = new Roo.BorderLayout(document.body, {
43520 preferredTabWidth: 150
43525 var CP = Roo.ContentPanel;
43527 layout.beginUpdate();
43528 layout.add("north", new CP("north", "North"));
43529 layout.add("south", new CP("south", {title: "South", closable: true}));
43530 layout.add("west", new CP("west", {title: "West"}));
43531 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43532 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43533 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43534 layout.getRegion("center").showPanel("center1");
43535 layout.endUpdate();
43538 <b>The container the layout is rendered into can be either the body element or any other element.
43539 If it is not the body element, the container needs to either be an absolute positioned element,
43540 or you will need to add "position:relative" to the css of the container. You will also need to specify
43541 the container size if it is not the body element.</b>
43544 * Create a new BorderLayout
43545 * @param {String/HTMLElement/Element} container The container this layout is bound to
43546 * @param {Object} config Configuration options
43548 Roo.BorderLayout = function(container, config){
43549 config = config || {};
43550 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43551 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43552 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43553 var target = this.factory.validRegions[i];
43554 if(config[target]){
43555 this.addRegion(target, config[target]);
43560 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43562 * Creates and adds a new region if it doesn't already exist.
43563 * @param {String} target The target region key (north, south, east, west or center).
43564 * @param {Object} config The regions config object
43565 * @return {BorderLayoutRegion} The new region
43567 addRegion : function(target, config){
43568 if(!this.regions[target]){
43569 var r = this.factory.create(target, this, config);
43570 this.bindRegion(target, r);
43572 return this.regions[target];
43576 bindRegion : function(name, r){
43577 this.regions[name] = r;
43578 r.on("visibilitychange", this.layout, this);
43579 r.on("paneladded", this.layout, this);
43580 r.on("panelremoved", this.layout, this);
43581 r.on("invalidated", this.layout, this);
43582 r.on("resized", this.onRegionResized, this);
43583 r.on("collapsed", this.onRegionCollapsed, this);
43584 r.on("expanded", this.onRegionExpanded, this);
43588 * Performs a layout update.
43590 layout : function(){
43591 if(this.updating) return;
43592 var size = this.getViewSize();
43593 var w = size.width;
43594 var h = size.height;
43599 //var x = 0, y = 0;
43601 var rs = this.regions;
43602 var north = rs["north"];
43603 var south = rs["south"];
43604 var west = rs["west"];
43605 var east = rs["east"];
43606 var center = rs["center"];
43607 //if(this.hideOnLayout){ // not supported anymore
43608 //c.el.setStyle("display", "none");
43610 if(north && north.isVisible()){
43611 var b = north.getBox();
43612 var m = north.getMargins();
43613 b.width = w - (m.left+m.right);
43616 centerY = b.height + b.y + m.bottom;
43617 centerH -= centerY;
43618 north.updateBox(this.safeBox(b));
43620 if(south && south.isVisible()){
43621 var b = south.getBox();
43622 var m = south.getMargins();
43623 b.width = w - (m.left+m.right);
43625 var totalHeight = (b.height + m.top + m.bottom);
43626 b.y = h - totalHeight + m.top;
43627 centerH -= totalHeight;
43628 south.updateBox(this.safeBox(b));
43630 if(west && west.isVisible()){
43631 var b = west.getBox();
43632 var m = west.getMargins();
43633 b.height = centerH - (m.top+m.bottom);
43635 b.y = centerY + m.top;
43636 var totalWidth = (b.width + m.left + m.right);
43637 centerX += totalWidth;
43638 centerW -= totalWidth;
43639 west.updateBox(this.safeBox(b));
43641 if(east && east.isVisible()){
43642 var b = east.getBox();
43643 var m = east.getMargins();
43644 b.height = centerH - (m.top+m.bottom);
43645 var totalWidth = (b.width + m.left + m.right);
43646 b.x = w - totalWidth + m.left;
43647 b.y = centerY + m.top;
43648 centerW -= totalWidth;
43649 east.updateBox(this.safeBox(b));
43652 var m = center.getMargins();
43654 x: centerX + m.left,
43655 y: centerY + m.top,
43656 width: centerW - (m.left+m.right),
43657 height: centerH - (m.top+m.bottom)
43659 //if(this.hideOnLayout){
43660 //center.el.setStyle("display", "block");
43662 center.updateBox(this.safeBox(centerBox));
43665 this.fireEvent("layout", this);
43669 safeBox : function(box){
43670 box.width = Math.max(0, box.width);
43671 box.height = Math.max(0, box.height);
43676 * Adds a ContentPanel (or subclass) to this layout.
43677 * @param {String} target The target region key (north, south, east, west or center).
43678 * @param {Roo.ContentPanel} panel The panel to add
43679 * @return {Roo.ContentPanel} The added panel
43681 add : function(target, panel){
43683 target = target.toLowerCase();
43684 return this.regions[target].add(panel);
43688 * Remove a ContentPanel (or subclass) to this layout.
43689 * @param {String} target The target region key (north, south, east, west or center).
43690 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43691 * @return {Roo.ContentPanel} The removed panel
43693 remove : function(target, panel){
43694 target = target.toLowerCase();
43695 return this.regions[target].remove(panel);
43699 * Searches all regions for a panel with the specified id
43700 * @param {String} panelId
43701 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43703 findPanel : function(panelId){
43704 var rs = this.regions;
43705 for(var target in rs){
43706 if(typeof rs[target] != "function"){
43707 var p = rs[target].getPanel(panelId);
43717 * Searches all regions for a panel with the specified id and activates (shows) it.
43718 * @param {String/ContentPanel} panelId The panels id or the panel itself
43719 * @return {Roo.ContentPanel} The shown panel or null
43721 showPanel : function(panelId) {
43722 var rs = this.regions;
43723 for(var target in rs){
43724 var r = rs[target];
43725 if(typeof r != "function"){
43726 if(r.hasPanel(panelId)){
43727 return r.showPanel(panelId);
43735 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43736 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43738 restoreState : function(provider){
43740 provider = Roo.state.Manager;
43742 var sm = new Roo.LayoutStateManager();
43743 sm.init(this, provider);
43747 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43748 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43749 * a valid ContentPanel config object. Example:
43751 // Create the main layout
43752 var layout = new Roo.BorderLayout('main-ct', {
43763 // Create and add multiple ContentPanels at once via configs
43766 id: 'source-files',
43768 title:'Ext Source Files',
43781 * @param {Object} regions An object containing ContentPanel configs by region name
43783 batchAdd : function(regions){
43784 this.beginUpdate();
43785 for(var rname in regions){
43786 var lr = this.regions[rname];
43788 this.addTypedPanels(lr, regions[rname]);
43795 addTypedPanels : function(lr, ps){
43796 if(typeof ps == 'string'){
43797 lr.add(new Roo.ContentPanel(ps));
43799 else if(ps instanceof Array){
43800 for(var i =0, len = ps.length; i < len; i++){
43801 this.addTypedPanels(lr, ps[i]);
43804 else if(!ps.events){ // raw config?
43806 delete ps.el; // prevent conflict
43807 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43809 else { // panel object assumed!
43814 * Adds a xtype elements to the layout.
43818 xtype : 'ContentPanel',
43825 xtype : 'NestedLayoutPanel',
43831 items : [ ... list of content panels or nested layout panels.. ]
43835 * @param {Object} cfg Xtype definition of item to add.
43837 addxtype : function(cfg)
43839 // basically accepts a pannel...
43840 // can accept a layout region..!?!?
43841 // console.log('BorderLayout add ' + cfg.xtype)
43843 if (!cfg.xtype.match(/Panel$/)) {
43847 var region = cfg.region;
43853 xitems = cfg.items;
43860 case 'ContentPanel': // ContentPanel (el, cfg)
43861 case 'ScrollPanel': // ContentPanel (el, cfg)
43862 if(cfg.autoCreate) {
43863 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43865 var el = this.el.createChild();
43866 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43869 this.add(region, ret);
43873 case 'TreePanel': // our new panel!
43874 cfg.el = this.el.createChild();
43875 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43876 this.add(region, ret);
43879 case 'NestedLayoutPanel':
43880 // create a new Layout (which is a Border Layout...
43881 var el = this.el.createChild();
43882 var clayout = cfg.layout;
43884 clayout.items = clayout.items || [];
43885 // replace this exitems with the clayout ones..
43886 xitems = clayout.items;
43889 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43890 cfg.background = false;
43892 var layout = new Roo.BorderLayout(el, clayout);
43894 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43895 //console.log('adding nested layout panel ' + cfg.toSource());
43896 this.add(region, ret);
43902 // needs grid and region
43904 //var el = this.getRegion(region).el.createChild();
43905 var el = this.el.createChild();
43906 // create the grid first...
43908 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43910 if (region == 'center' && this.active ) {
43911 cfg.background = false;
43913 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43915 this.add(region, ret);
43916 if (cfg.background) {
43917 ret.on('activate', function(gp) {
43918 if (!gp.grid.rendered) {
43931 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43933 // GridPanel (grid, cfg)
43936 this.beginUpdate();
43938 Roo.each(xitems, function(i) {
43948 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43949 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43950 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43951 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43954 var CP = Roo.ContentPanel;
43956 var layout = Roo.BorderLayout.create({
43960 panels: [new CP("north", "North")]
43969 panels: [new CP("west", {title: "West"})]
43978 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43987 panels: [new CP("south", {title: "South", closable: true})]
43994 preferredTabWidth: 150,
43996 new CP("center1", {title: "Close Me", closable: true}),
43997 new CP("center2", {title: "Center Panel", closable: false})
44002 layout.getRegion("center").showPanel("center1");
44007 Roo.BorderLayout.create = function(config, targetEl){
44008 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44009 layout.beginUpdate();
44010 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44011 for(var j = 0, jlen = regions.length; j < jlen; j++){
44012 var lr = regions[j];
44013 if(layout.regions[lr] && config[lr].panels){
44014 var r = layout.regions[lr];
44015 var ps = config[lr].panels;
44016 layout.addTypedPanels(r, ps);
44019 layout.endUpdate();
44024 Roo.BorderLayout.RegionFactory = {
44026 validRegions : ["north","south","east","west","center"],
44029 create : function(target, mgr, config){
44030 target = target.toLowerCase();
44031 if(config.lightweight || config.basic){
44032 return new Roo.BasicLayoutRegion(mgr, config, target);
44036 return new Roo.NorthLayoutRegion(mgr, config);
44038 return new Roo.SouthLayoutRegion(mgr, config);
44040 return new Roo.EastLayoutRegion(mgr, config);
44042 return new Roo.WestLayoutRegion(mgr, config);
44044 return new Roo.CenterLayoutRegion(mgr, config);
44046 throw 'Layout region "'+target+'" not supported.';
44050 * Ext JS Library 1.1.1
44051 * Copyright(c) 2006-2007, Ext JS, LLC.
44053 * Originally Released Under LGPL - original licence link has changed is not relivant.
44056 * <script type="text/javascript">
44060 * @class Roo.BasicLayoutRegion
44061 * @extends Roo.util.Observable
44062 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44063 * and does not have a titlebar, tabs or any other features. All it does is size and position
44064 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44066 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
44068 this.position = pos;
44071 * @scope Roo.BasicLayoutRegion
44075 * @event beforeremove
44076 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
44077 * @param {Roo.LayoutRegion} this
44078 * @param {Roo.ContentPanel} panel The panel
44079 * @param {Object} e The cancel event object
44081 "beforeremove" : true,
44083 * @event invalidated
44084 * Fires when the layout for this region is changed.
44085 * @param {Roo.LayoutRegion} this
44087 "invalidated" : true,
44089 * @event visibilitychange
44090 * Fires when this region is shown or hidden
44091 * @param {Roo.LayoutRegion} this
44092 * @param {Boolean} visibility true or false
44094 "visibilitychange" : true,
44096 * @event paneladded
44097 * Fires when a panel is added.
44098 * @param {Roo.LayoutRegion} this
44099 * @param {Roo.ContentPanel} panel The panel
44101 "paneladded" : true,
44103 * @event panelremoved
44104 * Fires when a panel is removed.
44105 * @param {Roo.LayoutRegion} this
44106 * @param {Roo.ContentPanel} panel The panel
44108 "panelremoved" : true,
44111 * Fires when this region is collapsed.
44112 * @param {Roo.LayoutRegion} this
44114 "collapsed" : true,
44117 * Fires when this region is expanded.
44118 * @param {Roo.LayoutRegion} this
44123 * Fires when this region is slid into view.
44124 * @param {Roo.LayoutRegion} this
44126 "slideshow" : true,
44129 * Fires when this region slides out of view.
44130 * @param {Roo.LayoutRegion} this
44132 "slidehide" : true,
44134 * @event panelactivated
44135 * Fires when a panel is activated.
44136 * @param {Roo.LayoutRegion} this
44137 * @param {Roo.ContentPanel} panel The activated panel
44139 "panelactivated" : true,
44142 * Fires when the user resizes this region.
44143 * @param {Roo.LayoutRegion} this
44144 * @param {Number} newSize The new size (width for east/west, height for north/south)
44148 /** A collection of panels in this region. @type Roo.util.MixedCollection */
44149 this.panels = new Roo.util.MixedCollection();
44150 this.panels.getKey = this.getPanelId.createDelegate(this);
44152 this.activePanel = null;
44153 // ensure listeners are added...
44155 if (config.listeners || config.events) {
44156 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
44157 listeners : config.listeners || {},
44158 events : config.events || {}
44162 if(skipConfig !== true){
44163 this.applyConfig(config);
44167 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
44168 getPanelId : function(p){
44172 applyConfig : function(config){
44173 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44174 this.config = config;
44179 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
44180 * the width, for horizontal (north, south) the height.
44181 * @param {Number} newSize The new width or height
44183 resizeTo : function(newSize){
44184 var el = this.el ? this.el :
44185 (this.activePanel ? this.activePanel.getEl() : null);
44187 switch(this.position){
44190 el.setWidth(newSize);
44191 this.fireEvent("resized", this, newSize);
44195 el.setHeight(newSize);
44196 this.fireEvent("resized", this, newSize);
44202 getBox : function(){
44203 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
44206 getMargins : function(){
44207 return this.margins;
44210 updateBox : function(box){
44212 var el = this.activePanel.getEl();
44213 el.dom.style.left = box.x + "px";
44214 el.dom.style.top = box.y + "px";
44215 this.activePanel.setSize(box.width, box.height);
44219 * Returns the container element for this region.
44220 * @return {Roo.Element}
44222 getEl : function(){
44223 return this.activePanel;
44227 * Returns true if this region is currently visible.
44228 * @return {Boolean}
44230 isVisible : function(){
44231 return this.activePanel ? true : false;
44234 setActivePanel : function(panel){
44235 panel = this.getPanel(panel);
44236 if(this.activePanel && this.activePanel != panel){
44237 this.activePanel.setActiveState(false);
44238 this.activePanel.getEl().setLeftTop(-10000,-10000);
44240 this.activePanel = panel;
44241 panel.setActiveState(true);
44243 panel.setSize(this.box.width, this.box.height);
44245 this.fireEvent("panelactivated", this, panel);
44246 this.fireEvent("invalidated");
44250 * Show the specified panel.
44251 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
44252 * @return {Roo.ContentPanel} The shown panel or null
44254 showPanel : function(panel){
44255 if(panel = this.getPanel(panel)){
44256 this.setActivePanel(panel);
44262 * Get the active panel for this region.
44263 * @return {Roo.ContentPanel} The active panel or null
44265 getActivePanel : function(){
44266 return this.activePanel;
44270 * Add the passed ContentPanel(s)
44271 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44272 * @return {Roo.ContentPanel} The panel added (if only one was added)
44274 add : function(panel){
44275 if(arguments.length > 1){
44276 for(var i = 0, len = arguments.length; i < len; i++) {
44277 this.add(arguments[i]);
44281 if(this.hasPanel(panel)){
44282 this.showPanel(panel);
44285 var el = panel.getEl();
44286 if(el.dom.parentNode != this.mgr.el.dom){
44287 this.mgr.el.dom.appendChild(el.dom);
44289 if(panel.setRegion){
44290 panel.setRegion(this);
44292 this.panels.add(panel);
44293 el.setStyle("position", "absolute");
44294 if(!panel.background){
44295 this.setActivePanel(panel);
44296 if(this.config.initialSize && this.panels.getCount()==1){
44297 this.resizeTo(this.config.initialSize);
44300 this.fireEvent("paneladded", this, panel);
44305 * Returns true if the panel is in this region.
44306 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44307 * @return {Boolean}
44309 hasPanel : function(panel){
44310 if(typeof panel == "object"){ // must be panel obj
44311 panel = panel.getId();
44313 return this.getPanel(panel) ? true : false;
44317 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44318 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44319 * @param {Boolean} preservePanel Overrides the config preservePanel option
44320 * @return {Roo.ContentPanel} The panel that was removed
44322 remove : function(panel, preservePanel){
44323 panel = this.getPanel(panel);
44328 this.fireEvent("beforeremove", this, panel, e);
44329 if(e.cancel === true){
44332 var panelId = panel.getId();
44333 this.panels.removeKey(panelId);
44338 * Returns the panel specified or null if it's not in this region.
44339 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44340 * @return {Roo.ContentPanel}
44342 getPanel : function(id){
44343 if(typeof id == "object"){ // must be panel obj
44346 return this.panels.get(id);
44350 * Returns this regions position (north/south/east/west/center).
44353 getPosition: function(){
44354 return this.position;
44358 * Ext JS Library 1.1.1
44359 * Copyright(c) 2006-2007, Ext JS, LLC.
44361 * Originally Released Under LGPL - original licence link has changed is not relivant.
44364 * <script type="text/javascript">
44368 * @class Roo.LayoutRegion
44369 * @extends Roo.BasicLayoutRegion
44370 * This class represents a region in a layout manager.
44371 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44372 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44373 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44374 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44375 * @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})
44376 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44377 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44378 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44379 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44380 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44381 * @cfg {String} title The title for the region (overrides panel titles)
44382 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44383 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44384 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44385 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44386 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44387 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44388 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44389 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44390 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44391 * @cfg {Boolean} showPin True to show a pin button
44392 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44393 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44394 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44395 * @cfg {Number} width For East/West panels
44396 * @cfg {Number} height For North/South panels
44397 * @cfg {Boolean} split To show the splitter
44399 Roo.LayoutRegion = function(mgr, config, pos){
44400 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44401 var dh = Roo.DomHelper;
44402 /** This region's container element
44403 * @type Roo.Element */
44404 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44405 /** This region's title element
44406 * @type Roo.Element */
44408 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44409 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44410 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44412 this.titleEl.enableDisplayMode();
44413 /** This region's title text element
44414 * @type HTMLElement */
44415 this.titleTextEl = this.titleEl.dom.firstChild;
44416 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44417 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44418 this.closeBtn.enableDisplayMode();
44419 this.closeBtn.on("click", this.closeClicked, this);
44420 this.closeBtn.hide();
44422 this.createBody(config);
44423 this.visible = true;
44424 this.collapsed = false;
44426 if(config.hideWhenEmpty){
44428 this.on("paneladded", this.validateVisibility, this);
44429 this.on("panelremoved", this.validateVisibility, this);
44431 this.applyConfig(config);
44434 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44436 createBody : function(){
44437 /** This region's body element
44438 * @type Roo.Element */
44439 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44442 applyConfig : function(c){
44443 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44444 var dh = Roo.DomHelper;
44445 if(c.titlebar !== false){
44446 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44447 this.collapseBtn.on("click", this.collapse, this);
44448 this.collapseBtn.enableDisplayMode();
44450 if(c.showPin === true || this.showPin){
44451 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44452 this.stickBtn.enableDisplayMode();
44453 this.stickBtn.on("click", this.expand, this);
44454 this.stickBtn.hide();
44457 /** This region's collapsed element
44458 * @type Roo.Element */
44459 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44460 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44462 if(c.floatable !== false){
44463 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44464 this.collapsedEl.on("click", this.collapseClick, this);
44467 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44468 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44469 id: "message", unselectable: "on", style:{"float":"left"}});
44470 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44472 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44473 this.expandBtn.on("click", this.expand, this);
44475 if(this.collapseBtn){
44476 this.collapseBtn.setVisible(c.collapsible == true);
44478 this.cmargins = c.cmargins || this.cmargins ||
44479 (this.position == "west" || this.position == "east" ?
44480 {top: 0, left: 2, right:2, bottom: 0} :
44481 {top: 2, left: 0, right:0, bottom: 2});
44482 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44483 this.bottomTabs = c.tabPosition != "top";
44484 this.autoScroll = c.autoScroll || false;
44485 if(this.autoScroll){
44486 this.bodyEl.setStyle("overflow", "auto");
44488 this.bodyEl.setStyle("overflow", "hidden");
44490 //if(c.titlebar !== false){
44491 if((!c.titlebar && !c.title) || c.titlebar === false){
44492 this.titleEl.hide();
44494 this.titleEl.show();
44496 this.titleTextEl.innerHTML = c.title;
44500 this.duration = c.duration || .30;
44501 this.slideDuration = c.slideDuration || .45;
44504 this.collapse(true);
44511 * Returns true if this region is currently visible.
44512 * @return {Boolean}
44514 isVisible : function(){
44515 return this.visible;
44519 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44520 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44522 setCollapsedTitle : function(title){
44523 title = title || " ";
44524 if(this.collapsedTitleTextEl){
44525 this.collapsedTitleTextEl.innerHTML = title;
44529 getBox : function(){
44531 if(!this.collapsed){
44532 b = this.el.getBox(false, true);
44534 b = this.collapsedEl.getBox(false, true);
44539 getMargins : function(){
44540 return this.collapsed ? this.cmargins : this.margins;
44543 highlight : function(){
44544 this.el.addClass("x-layout-panel-dragover");
44547 unhighlight : function(){
44548 this.el.removeClass("x-layout-panel-dragover");
44551 updateBox : function(box){
44553 if(!this.collapsed){
44554 this.el.dom.style.left = box.x + "px";
44555 this.el.dom.style.top = box.y + "px";
44556 this.updateBody(box.width, box.height);
44558 this.collapsedEl.dom.style.left = box.x + "px";
44559 this.collapsedEl.dom.style.top = box.y + "px";
44560 this.collapsedEl.setSize(box.width, box.height);
44563 this.tabs.autoSizeTabs();
44567 updateBody : function(w, h){
44569 this.el.setWidth(w);
44570 w -= this.el.getBorderWidth("rl");
44571 if(this.config.adjustments){
44572 w += this.config.adjustments[0];
44576 this.el.setHeight(h);
44577 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44578 h -= this.el.getBorderWidth("tb");
44579 if(this.config.adjustments){
44580 h += this.config.adjustments[1];
44582 this.bodyEl.setHeight(h);
44584 h = this.tabs.syncHeight(h);
44587 if(this.panelSize){
44588 w = w !== null ? w : this.panelSize.width;
44589 h = h !== null ? h : this.panelSize.height;
44591 if(this.activePanel){
44592 var el = this.activePanel.getEl();
44593 w = w !== null ? w : el.getWidth();
44594 h = h !== null ? h : el.getHeight();
44595 this.panelSize = {width: w, height: h};
44596 this.activePanel.setSize(w, h);
44598 if(Roo.isIE && this.tabs){
44599 this.tabs.el.repaint();
44604 * Returns the container element for this region.
44605 * @return {Roo.Element}
44607 getEl : function(){
44612 * Hides this region.
44615 if(!this.collapsed){
44616 this.el.dom.style.left = "-2000px";
44619 this.collapsedEl.dom.style.left = "-2000px";
44620 this.collapsedEl.hide();
44622 this.visible = false;
44623 this.fireEvent("visibilitychange", this, false);
44627 * Shows this region if it was previously hidden.
44630 if(!this.collapsed){
44633 this.collapsedEl.show();
44635 this.visible = true;
44636 this.fireEvent("visibilitychange", this, true);
44639 closeClicked : function(){
44640 if(this.activePanel){
44641 this.remove(this.activePanel);
44645 collapseClick : function(e){
44647 e.stopPropagation();
44650 e.stopPropagation();
44656 * Collapses this region.
44657 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44659 collapse : function(skipAnim){
44660 if(this.collapsed) return;
44661 this.collapsed = true;
44663 this.split.el.hide();
44665 if(this.config.animate && skipAnim !== true){
44666 this.fireEvent("invalidated", this);
44667 this.animateCollapse();
44669 this.el.setLocation(-20000,-20000);
44671 this.collapsedEl.show();
44672 this.fireEvent("collapsed", this);
44673 this.fireEvent("invalidated", this);
44677 animateCollapse : function(){
44682 * Expands this region if it was previously collapsed.
44683 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44684 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44686 expand : function(e, skipAnim){
44687 if(e) e.stopPropagation();
44688 if(!this.collapsed || this.el.hasActiveFx()) return;
44690 this.afterSlideIn();
44693 this.collapsed = false;
44694 if(this.config.animate && skipAnim !== true){
44695 this.animateExpand();
44699 this.split.el.show();
44701 this.collapsedEl.setLocation(-2000,-2000);
44702 this.collapsedEl.hide();
44703 this.fireEvent("invalidated", this);
44704 this.fireEvent("expanded", this);
44708 animateExpand : function(){
44712 initTabs : function(){
44713 this.bodyEl.setStyle("overflow", "hidden");
44714 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44715 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44716 disableTooltips: this.config.disableTabTips
44718 if(this.config.hideTabs){
44719 ts.stripWrap.setDisplayed(false);
44722 ts.resizeTabs = this.config.resizeTabs === true;
44723 ts.minTabWidth = this.config.minTabWidth || 40;
44724 ts.maxTabWidth = this.config.maxTabWidth || 250;
44725 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44726 ts.monitorResize = false;
44727 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44728 ts.bodyEl.addClass('x-layout-tabs-body');
44729 this.panels.each(this.initPanelAsTab, this);
44732 initPanelAsTab : function(panel){
44733 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44734 this.config.closeOnTab && panel.isClosable());
44735 if(panel.tabTip !== undefined){
44736 ti.setTooltip(panel.tabTip);
44738 ti.on("activate", function(){
44739 this.setActivePanel(panel);
44741 if(this.config.closeOnTab){
44742 ti.on("beforeclose", function(t, e){
44744 this.remove(panel);
44750 updatePanelTitle : function(panel, title){
44751 if(this.activePanel == panel){
44752 this.updateTitle(title);
44755 var ti = this.tabs.getTab(panel.getEl().id);
44757 if(panel.tabTip !== undefined){
44758 ti.setTooltip(panel.tabTip);
44763 updateTitle : function(title){
44764 if(this.titleTextEl && !this.config.title){
44765 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44769 setActivePanel : function(panel){
44770 panel = this.getPanel(panel);
44771 if(this.activePanel && this.activePanel != panel){
44772 this.activePanel.setActiveState(false);
44774 this.activePanel = panel;
44775 panel.setActiveState(true);
44776 if(this.panelSize){
44777 panel.setSize(this.panelSize.width, this.panelSize.height);
44780 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44782 this.updateTitle(panel.getTitle());
44784 this.fireEvent("invalidated", this);
44786 this.fireEvent("panelactivated", this, panel);
44790 * Shows the specified panel.
44791 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44792 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44794 showPanel : function(panel){
44795 if(panel = this.getPanel(panel)){
44797 var tab = this.tabs.getTab(panel.getEl().id);
44798 if(tab.isHidden()){
44799 this.tabs.unhideTab(tab.id);
44803 this.setActivePanel(panel);
44810 * Get the active panel for this region.
44811 * @return {Roo.ContentPanel} The active panel or null
44813 getActivePanel : function(){
44814 return this.activePanel;
44817 validateVisibility : function(){
44818 if(this.panels.getCount() < 1){
44819 this.updateTitle(" ");
44820 this.closeBtn.hide();
44823 if(!this.isVisible()){
44830 * Adds the passed ContentPanel(s) to this region.
44831 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44832 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44834 add : function(panel){
44835 if(arguments.length > 1){
44836 for(var i = 0, len = arguments.length; i < len; i++) {
44837 this.add(arguments[i]);
44841 if(this.hasPanel(panel)){
44842 this.showPanel(panel);
44845 panel.setRegion(this);
44846 this.panels.add(panel);
44847 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44848 this.bodyEl.dom.appendChild(panel.getEl().dom);
44849 if(panel.background !== true){
44850 this.setActivePanel(panel);
44852 this.fireEvent("paneladded", this, panel);
44858 this.initPanelAsTab(panel);
44860 if(panel.background !== true){
44861 this.tabs.activate(panel.getEl().id);
44863 this.fireEvent("paneladded", this, panel);
44868 * Hides the tab for the specified panel.
44869 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44871 hidePanel : function(panel){
44872 if(this.tabs && (panel = this.getPanel(panel))){
44873 this.tabs.hideTab(panel.getEl().id);
44878 * Unhides the tab for a previously hidden panel.
44879 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44881 unhidePanel : function(panel){
44882 if(this.tabs && (panel = this.getPanel(panel))){
44883 this.tabs.unhideTab(panel.getEl().id);
44887 clearPanels : function(){
44888 while(this.panels.getCount() > 0){
44889 this.remove(this.panels.first());
44894 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44895 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44896 * @param {Boolean} preservePanel Overrides the config preservePanel option
44897 * @return {Roo.ContentPanel} The panel that was removed
44899 remove : function(panel, preservePanel){
44900 panel = this.getPanel(panel);
44905 this.fireEvent("beforeremove", this, panel, e);
44906 if(e.cancel === true){
44909 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44910 var panelId = panel.getId();
44911 this.panels.removeKey(panelId);
44913 document.body.appendChild(panel.getEl().dom);
44916 this.tabs.removeTab(panel.getEl().id);
44917 }else if (!preservePanel){
44918 this.bodyEl.dom.removeChild(panel.getEl().dom);
44920 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44921 var p = this.panels.first();
44922 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44923 tempEl.appendChild(p.getEl().dom);
44924 this.bodyEl.update("");
44925 this.bodyEl.dom.appendChild(p.getEl().dom);
44927 this.updateTitle(p.getTitle());
44929 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44930 this.setActivePanel(p);
44932 panel.setRegion(null);
44933 if(this.activePanel == panel){
44934 this.activePanel = null;
44936 if(this.config.autoDestroy !== false && preservePanel !== true){
44937 try{panel.destroy();}catch(e){}
44939 this.fireEvent("panelremoved", this, panel);
44944 * Returns the TabPanel component used by this region
44945 * @return {Roo.TabPanel}
44947 getTabs : function(){
44951 createTool : function(parentEl, className){
44952 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44953 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44954 btn.addClassOnOver("x-layout-tools-button-over");
44959 * Ext JS Library 1.1.1
44960 * Copyright(c) 2006-2007, Ext JS, LLC.
44962 * Originally Released Under LGPL - original licence link has changed is not relivant.
44965 * <script type="text/javascript">
44971 * @class Roo.SplitLayoutRegion
44972 * @extends Roo.LayoutRegion
44973 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44975 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44976 this.cursor = cursor;
44977 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44980 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44981 splitTip : "Drag to resize.",
44982 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44983 useSplitTips : false,
44985 applyConfig : function(config){
44986 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44989 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44990 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44991 /** The SplitBar for this region
44992 * @type Roo.SplitBar */
44993 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44994 this.split.on("moved", this.onSplitMove, this);
44995 this.split.useShim = config.useShim === true;
44996 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44997 if(this.useSplitTips){
44998 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
45000 if(config.collapsible){
45001 this.split.el.on("dblclick", this.collapse, this);
45004 if(typeof config.minSize != "undefined"){
45005 this.split.minSize = config.minSize;
45007 if(typeof config.maxSize != "undefined"){
45008 this.split.maxSize = config.maxSize;
45010 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45011 this.hideSplitter();
45016 getHMaxSize : function(){
45017 var cmax = this.config.maxSize || 10000;
45018 var center = this.mgr.getRegion("center");
45019 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45022 getVMaxSize : function(){
45023 var cmax = this.config.maxSize || 10000;
45024 var center = this.mgr.getRegion("center");
45025 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45028 onSplitMove : function(split, newSize){
45029 this.fireEvent("resized", this, newSize);
45033 * Returns the {@link Roo.SplitBar} for this region.
45034 * @return {Roo.SplitBar}
45036 getSplitBar : function(){
45041 this.hideSplitter();
45042 Roo.SplitLayoutRegion.superclass.hide.call(this);
45045 hideSplitter : function(){
45047 this.split.el.setLocation(-2000,-2000);
45048 this.split.el.hide();
45054 this.split.el.show();
45056 Roo.SplitLayoutRegion.superclass.show.call(this);
45059 beforeSlide: function(){
45060 if(Roo.isGecko){// firefox overflow auto bug workaround
45061 this.bodyEl.clip();
45062 if(this.tabs) this.tabs.bodyEl.clip();
45063 if(this.activePanel){
45064 this.activePanel.getEl().clip();
45066 if(this.activePanel.beforeSlide){
45067 this.activePanel.beforeSlide();
45073 afterSlide : function(){
45074 if(Roo.isGecko){// firefox overflow auto bug workaround
45075 this.bodyEl.unclip();
45076 if(this.tabs) this.tabs.bodyEl.unclip();
45077 if(this.activePanel){
45078 this.activePanel.getEl().unclip();
45079 if(this.activePanel.afterSlide){
45080 this.activePanel.afterSlide();
45086 initAutoHide : function(){
45087 if(this.autoHide !== false){
45088 if(!this.autoHideHd){
45089 var st = new Roo.util.DelayedTask(this.slideIn, this);
45090 this.autoHideHd = {
45091 "mouseout": function(e){
45092 if(!e.within(this.el, true)){
45096 "mouseover" : function(e){
45102 this.el.on(this.autoHideHd);
45106 clearAutoHide : function(){
45107 if(this.autoHide !== false){
45108 this.el.un("mouseout", this.autoHideHd.mouseout);
45109 this.el.un("mouseover", this.autoHideHd.mouseover);
45113 clearMonitor : function(){
45114 Roo.get(document).un("click", this.slideInIf, this);
45117 // these names are backwards but not changed for compat
45118 slideOut : function(){
45119 if(this.isSlid || this.el.hasActiveFx()){
45122 this.isSlid = true;
45123 if(this.collapseBtn){
45124 this.collapseBtn.hide();
45126 this.closeBtnState = this.closeBtn.getStyle('display');
45127 this.closeBtn.hide();
45129 this.stickBtn.show();
45132 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
45133 this.beforeSlide();
45134 this.el.setStyle("z-index", 10001);
45135 this.el.slideIn(this.getSlideAnchor(), {
45136 callback: function(){
45138 this.initAutoHide();
45139 Roo.get(document).on("click", this.slideInIf, this);
45140 this.fireEvent("slideshow", this);
45147 afterSlideIn : function(){
45148 this.clearAutoHide();
45149 this.isSlid = false;
45150 this.clearMonitor();
45151 this.el.setStyle("z-index", "");
45152 if(this.collapseBtn){
45153 this.collapseBtn.show();
45155 this.closeBtn.setStyle('display', this.closeBtnState);
45157 this.stickBtn.hide();
45159 this.fireEvent("slidehide", this);
45162 slideIn : function(cb){
45163 if(!this.isSlid || this.el.hasActiveFx()){
45167 this.isSlid = false;
45168 this.beforeSlide();
45169 this.el.slideOut(this.getSlideAnchor(), {
45170 callback: function(){
45171 this.el.setLeftTop(-10000, -10000);
45173 this.afterSlideIn();
45181 slideInIf : function(e){
45182 if(!e.within(this.el)){
45187 animateCollapse : function(){
45188 this.beforeSlide();
45189 this.el.setStyle("z-index", 20000);
45190 var anchor = this.getSlideAnchor();
45191 this.el.slideOut(anchor, {
45192 callback : function(){
45193 this.el.setStyle("z-index", "");
45194 this.collapsedEl.slideIn(anchor, {duration:.3});
45196 this.el.setLocation(-10000,-10000);
45198 this.fireEvent("collapsed", this);
45205 animateExpand : function(){
45206 this.beforeSlide();
45207 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
45208 this.el.setStyle("z-index", 20000);
45209 this.collapsedEl.hide({
45212 this.el.slideIn(this.getSlideAnchor(), {
45213 callback : function(){
45214 this.el.setStyle("z-index", "");
45217 this.split.el.show();
45219 this.fireEvent("invalidated", this);
45220 this.fireEvent("expanded", this);
45248 getAnchor : function(){
45249 return this.anchors[this.position];
45252 getCollapseAnchor : function(){
45253 return this.canchors[this.position];
45256 getSlideAnchor : function(){
45257 return this.sanchors[this.position];
45260 getAlignAdj : function(){
45261 var cm = this.cmargins;
45262 switch(this.position){
45278 getExpandAdj : function(){
45279 var c = this.collapsedEl, cm = this.cmargins;
45280 switch(this.position){
45282 return [-(cm.right+c.getWidth()+cm.left), 0];
45285 return [cm.right+c.getWidth()+cm.left, 0];
45288 return [0, -(cm.top+cm.bottom+c.getHeight())];
45291 return [0, cm.top+cm.bottom+c.getHeight()];
45297 * Ext JS Library 1.1.1
45298 * Copyright(c) 2006-2007, Ext JS, LLC.
45300 * Originally Released Under LGPL - original licence link has changed is not relivant.
45303 * <script type="text/javascript">
45306 * These classes are private internal classes
45308 Roo.CenterLayoutRegion = function(mgr, config){
45309 Roo.LayoutRegion.call(this, mgr, config, "center");
45310 this.visible = true;
45311 this.minWidth = config.minWidth || 20;
45312 this.minHeight = config.minHeight || 20;
45315 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45317 // center panel can't be hidden
45321 // center panel can't be hidden
45324 getMinWidth: function(){
45325 return this.minWidth;
45328 getMinHeight: function(){
45329 return this.minHeight;
45334 Roo.NorthLayoutRegion = function(mgr, config){
45335 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45337 this.split.placement = Roo.SplitBar.TOP;
45338 this.split.orientation = Roo.SplitBar.VERTICAL;
45339 this.split.el.addClass("x-layout-split-v");
45341 var size = config.initialSize || config.height;
45342 if(typeof size != "undefined"){
45343 this.el.setHeight(size);
45346 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45347 orientation: Roo.SplitBar.VERTICAL,
45348 getBox : function(){
45349 if(this.collapsed){
45350 return this.collapsedEl.getBox();
45352 var box = this.el.getBox();
45354 box.height += this.split.el.getHeight();
45359 updateBox : function(box){
45360 if(this.split && !this.collapsed){
45361 box.height -= this.split.el.getHeight();
45362 this.split.el.setLeft(box.x);
45363 this.split.el.setTop(box.y+box.height);
45364 this.split.el.setWidth(box.width);
45366 if(this.collapsed){
45367 this.updateBody(box.width, null);
45369 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45373 Roo.SouthLayoutRegion = function(mgr, config){
45374 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45376 this.split.placement = Roo.SplitBar.BOTTOM;
45377 this.split.orientation = Roo.SplitBar.VERTICAL;
45378 this.split.el.addClass("x-layout-split-v");
45380 var size = config.initialSize || config.height;
45381 if(typeof size != "undefined"){
45382 this.el.setHeight(size);
45385 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45386 orientation: Roo.SplitBar.VERTICAL,
45387 getBox : function(){
45388 if(this.collapsed){
45389 return this.collapsedEl.getBox();
45391 var box = this.el.getBox();
45393 var sh = this.split.el.getHeight();
45400 updateBox : function(box){
45401 if(this.split && !this.collapsed){
45402 var sh = this.split.el.getHeight();
45405 this.split.el.setLeft(box.x);
45406 this.split.el.setTop(box.y-sh);
45407 this.split.el.setWidth(box.width);
45409 if(this.collapsed){
45410 this.updateBody(box.width, null);
45412 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45416 Roo.EastLayoutRegion = function(mgr, config){
45417 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45419 this.split.placement = Roo.SplitBar.RIGHT;
45420 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45421 this.split.el.addClass("x-layout-split-h");
45423 var size = config.initialSize || config.width;
45424 if(typeof size != "undefined"){
45425 this.el.setWidth(size);
45428 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45429 orientation: Roo.SplitBar.HORIZONTAL,
45430 getBox : function(){
45431 if(this.collapsed){
45432 return this.collapsedEl.getBox();
45434 var box = this.el.getBox();
45436 var sw = this.split.el.getWidth();
45443 updateBox : function(box){
45444 if(this.split && !this.collapsed){
45445 var sw = this.split.el.getWidth();
45447 this.split.el.setLeft(box.x);
45448 this.split.el.setTop(box.y);
45449 this.split.el.setHeight(box.height);
45452 if(this.collapsed){
45453 this.updateBody(null, box.height);
45455 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45459 Roo.WestLayoutRegion = function(mgr, config){
45460 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45462 this.split.placement = Roo.SplitBar.LEFT;
45463 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45464 this.split.el.addClass("x-layout-split-h");
45466 var size = config.initialSize || config.width;
45467 if(typeof size != "undefined"){
45468 this.el.setWidth(size);
45471 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45472 orientation: Roo.SplitBar.HORIZONTAL,
45473 getBox : function(){
45474 if(this.collapsed){
45475 return this.collapsedEl.getBox();
45477 var box = this.el.getBox();
45479 box.width += this.split.el.getWidth();
45484 updateBox : function(box){
45485 if(this.split && !this.collapsed){
45486 var sw = this.split.el.getWidth();
45488 this.split.el.setLeft(box.x+box.width);
45489 this.split.el.setTop(box.y);
45490 this.split.el.setHeight(box.height);
45492 if(this.collapsed){
45493 this.updateBody(null, box.height);
45495 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45500 * Ext JS Library 1.1.1
45501 * Copyright(c) 2006-2007, Ext JS, LLC.
45503 * Originally Released Under LGPL - original licence link has changed is not relivant.
45506 * <script type="text/javascript">
45511 * Private internal class for reading and applying state
45513 Roo.LayoutStateManager = function(layout){
45514 // default empty state
45523 Roo.LayoutStateManager.prototype = {
45524 init : function(layout, provider){
45525 this.provider = provider;
45526 var state = provider.get(layout.id+"-layout-state");
45528 var wasUpdating = layout.isUpdating();
45530 layout.beginUpdate();
45532 for(var key in state){
45533 if(typeof state[key] != "function"){
45534 var rstate = state[key];
45535 var r = layout.getRegion(key);
45538 r.resizeTo(rstate.size);
45540 if(rstate.collapsed == true){
45543 r.expand(null, true);
45549 layout.endUpdate();
45551 this.state = state;
45553 this.layout = layout;
45554 layout.on("regionresized", this.onRegionResized, this);
45555 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45556 layout.on("regionexpanded", this.onRegionExpanded, this);
45559 storeState : function(){
45560 this.provider.set(this.layout.id+"-layout-state", this.state);
45563 onRegionResized : function(region, newSize){
45564 this.state[region.getPosition()].size = newSize;
45568 onRegionCollapsed : function(region){
45569 this.state[region.getPosition()].collapsed = true;
45573 onRegionExpanded : function(region){
45574 this.state[region.getPosition()].collapsed = false;
45579 * Ext JS Library 1.1.1
45580 * Copyright(c) 2006-2007, Ext JS, LLC.
45582 * Originally Released Under LGPL - original licence link has changed is not relivant.
45585 * <script type="text/javascript">
45588 * @class Roo.ContentPanel
45589 * @extends Roo.util.Observable
45590 * A basic ContentPanel element.
45591 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45592 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45593 * @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
45594 * @cfg {Boolean} closable True if the panel can be closed/removed
45595 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45596 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45597 * @cfg {Toolbar} toolbar A toolbar for this panel
45598 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45599 * @cfg {String} title The title for this panel
45600 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45601 * @cfg {String} url Calls {@link #setUrl} with this value
45602 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45603 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45604 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45606 * Create a new ContentPanel.
45607 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45608 * @param {String/Object} config A string to set only the title or a config object
45609 * @param {String} content (optional) Set the HTML content for this panel
45610 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45612 Roo.ContentPanel = function(el, config, content){
45616 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45620 if (config && config.parentLayout) {
45621 el = config.parentLayout.el.createChild();
45624 if(el.autoCreate){ // xtype is available if this is called from factory
45628 this.el = Roo.get(el);
45629 if(!this.el && config && config.autoCreate){
45630 if(typeof config.autoCreate == "object"){
45631 if(!config.autoCreate.id){
45632 config.autoCreate.id = config.id||el;
45634 this.el = Roo.DomHelper.append(document.body,
45635 config.autoCreate, true);
45637 this.el = Roo.DomHelper.append(document.body,
45638 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45641 this.closable = false;
45642 this.loaded = false;
45643 this.active = false;
45644 if(typeof config == "string"){
45645 this.title = config;
45647 Roo.apply(this, config);
45650 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45651 this.wrapEl = this.el.wrap();
45652 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45659 this.resizeEl = Roo.get(this.resizeEl, true);
45661 this.resizeEl = this.el;
45666 * Fires when this panel is activated.
45667 * @param {Roo.ContentPanel} this
45671 * @event deactivate
45672 * Fires when this panel is activated.
45673 * @param {Roo.ContentPanel} this
45675 "deactivate" : true,
45679 * Fires when this panel is resized if fitToFrame is true.
45680 * @param {Roo.ContentPanel} this
45681 * @param {Number} width The width after any component adjustments
45682 * @param {Number} height The height after any component adjustments
45686 if(this.autoScroll){
45687 this.resizeEl.setStyle("overflow", "auto");
45689 // fix randome scrolling
45690 this.el.on('scroll', function() {
45691 Roo.log('fix random scolling');
45692 this.scrollTo('top',0);
45695 content = content || this.content;
45697 this.setContent(content);
45699 if(config && config.url){
45700 this.setUrl(this.url, this.params, this.loadOnce);
45705 Roo.ContentPanel.superclass.constructor.call(this);
45708 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45710 setRegion : function(region){
45711 this.region = region;
45713 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45715 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45720 * Returns the toolbar for this Panel if one was configured.
45721 * @return {Roo.Toolbar}
45723 getToolbar : function(){
45724 return this.toolbar;
45727 setActiveState : function(active){
45728 this.active = active;
45730 this.fireEvent("deactivate", this);
45732 this.fireEvent("activate", this);
45736 * Updates this panel's element
45737 * @param {String} content The new content
45738 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45740 setContent : function(content, loadScripts){
45741 this.el.update(content, loadScripts);
45744 ignoreResize : function(w, h){
45745 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45748 this.lastSize = {width: w, height: h};
45753 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45754 * @return {Roo.UpdateManager} The UpdateManager
45756 getUpdateManager : function(){
45757 return this.el.getUpdateManager();
45760 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45761 * @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:
45764 url: "your-url.php",
45765 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45766 callback: yourFunction,
45767 scope: yourObject, //(optional scope)
45770 text: "Loading...",
45775 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45776 * 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.
45777 * @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}
45778 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45779 * @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.
45780 * @return {Roo.ContentPanel} this
45783 var um = this.el.getUpdateManager();
45784 um.update.apply(um, arguments);
45790 * 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.
45791 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45792 * @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)
45793 * @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)
45794 * @return {Roo.UpdateManager} The UpdateManager
45796 setUrl : function(url, params, loadOnce){
45797 if(this.refreshDelegate){
45798 this.removeListener("activate", this.refreshDelegate);
45800 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45801 this.on("activate", this.refreshDelegate);
45802 return this.el.getUpdateManager();
45805 _handleRefresh : function(url, params, loadOnce){
45806 if(!loadOnce || !this.loaded){
45807 var updater = this.el.getUpdateManager();
45808 updater.update(url, params, this._setLoaded.createDelegate(this));
45812 _setLoaded : function(){
45813 this.loaded = true;
45817 * Returns this panel's id
45820 getId : function(){
45825 * Returns this panel's element - used by regiosn to add.
45826 * @return {Roo.Element}
45828 getEl : function(){
45829 return this.wrapEl || this.el;
45832 adjustForComponents : function(width, height){
45833 if(this.resizeEl != this.el){
45834 width -= this.el.getFrameWidth('lr');
45835 height -= this.el.getFrameWidth('tb');
45838 var te = this.toolbar.getEl();
45839 height -= te.getHeight();
45840 te.setWidth(width);
45842 if(this.adjustments){
45843 width += this.adjustments[0];
45844 height += this.adjustments[1];
45846 return {"width": width, "height": height};
45849 setSize : function(width, height){
45850 if(this.fitToFrame && !this.ignoreResize(width, height)){
45851 if(this.fitContainer && this.resizeEl != this.el){
45852 this.el.setSize(width, height);
45854 var size = this.adjustForComponents(width, height);
45855 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45856 this.fireEvent('resize', this, size.width, size.height);
45861 * Returns this panel's title
45864 getTitle : function(){
45869 * Set this panel's title
45870 * @param {String} title
45872 setTitle : function(title){
45873 this.title = title;
45875 this.region.updatePanelTitle(this, title);
45880 * Returns true is this panel was configured to be closable
45881 * @return {Boolean}
45883 isClosable : function(){
45884 return this.closable;
45887 beforeSlide : function(){
45889 this.resizeEl.clip();
45892 afterSlide : function(){
45894 this.resizeEl.unclip();
45898 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45899 * Will fail silently if the {@link #setUrl} method has not been called.
45900 * This does not activate the panel, just updates its content.
45902 refresh : function(){
45903 if(this.refreshDelegate){
45904 this.loaded = false;
45905 this.refreshDelegate();
45910 * Destroys this panel
45912 destroy : function(){
45913 this.el.removeAllListeners();
45914 var tempEl = document.createElement("span");
45915 tempEl.appendChild(this.el.dom);
45916 tempEl.innerHTML = "";
45922 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45932 * @param {Object} cfg Xtype definition of item to add.
45935 addxtype : function(cfg) {
45937 if (cfg.xtype.match(/^Form$/)) {
45938 var el = this.el.createChild();
45940 this.form = new Roo.form.Form(cfg);
45943 if ( this.form.allItems.length) this.form.render(el.dom);
45946 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45948 cfg.el = this.el.appendChild(document.createElement("div"));
45950 var ret = new Roo[cfg.xtype](cfg);
45951 ret.render(false, ''); // render blank..
45961 * @class Roo.GridPanel
45962 * @extends Roo.ContentPanel
45964 * Create a new GridPanel.
45965 * @param {Roo.grid.Grid} grid The grid for this panel
45966 * @param {String/Object} config A string to set only the panel's title, or a config object
45968 Roo.GridPanel = function(grid, config){
45971 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45972 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45974 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45976 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45979 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45981 // xtype created footer. - not sure if will work as we normally have to render first..
45982 if (this.footer && !this.footer.el && this.footer.xtype) {
45984 this.footer.container = this.grid.getView().getFooterPanel(true);
45985 this.footer.dataSource = this.grid.dataSource;
45986 this.footer = Roo.factory(this.footer, Roo);
45990 grid.monitorWindowResize = false; // turn off autosizing
45991 grid.autoHeight = false;
45992 grid.autoWidth = false;
45994 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45997 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45998 getId : function(){
45999 return this.grid.id;
46003 * Returns the grid for this panel
46004 * @return {Roo.grid.Grid}
46006 getGrid : function(){
46010 setSize : function(width, height){
46011 if(!this.ignoreResize(width, height)){
46012 var grid = this.grid;
46013 var size = this.adjustForComponents(width, height);
46014 grid.getGridEl().setSize(size.width, size.height);
46019 beforeSlide : function(){
46020 this.grid.getView().scroller.clip();
46023 afterSlide : function(){
46024 this.grid.getView().scroller.unclip();
46027 destroy : function(){
46028 this.grid.destroy();
46030 Roo.GridPanel.superclass.destroy.call(this);
46036 * @class Roo.NestedLayoutPanel
46037 * @extends Roo.ContentPanel
46039 * Create a new NestedLayoutPanel.
46042 * @param {Roo.BorderLayout} layout The layout for this panel
46043 * @param {String/Object} config A string to set only the title or a config object
46045 Roo.NestedLayoutPanel = function(layout, config)
46047 // construct with only one argument..
46048 /* FIXME - implement nicer consturctors
46049 if (layout.layout) {
46051 layout = config.layout;
46052 delete config.layout;
46054 if (layout.xtype && !layout.getEl) {
46055 // then layout needs constructing..
46056 layout = Roo.factory(layout, Roo);
46061 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
46063 layout.monitorWindowResize = false; // turn off autosizing
46064 this.layout = layout;
46065 this.layout.getEl().addClass("x-layout-nested-layout");
46072 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
46074 setSize : function(width, height){
46075 if(!this.ignoreResize(width, height)){
46076 var size = this.adjustForComponents(width, height);
46077 var el = this.layout.getEl();
46078 el.setSize(size.width, size.height);
46079 var touch = el.dom.offsetWidth;
46080 this.layout.layout();
46081 // ie requires a double layout on the first pass
46082 if(Roo.isIE && !this.initialized){
46083 this.initialized = true;
46084 this.layout.layout();
46089 // activate all subpanels if not currently active..
46091 setActiveState : function(active){
46092 this.active = active;
46094 this.fireEvent("deactivate", this);
46098 this.fireEvent("activate", this);
46099 // not sure if this should happen before or after..
46100 if (!this.layout) {
46101 return; // should not happen..
46104 for (var r in this.layout.regions) {
46105 reg = this.layout.getRegion(r);
46106 if (reg.getActivePanel()) {
46107 //reg.showPanel(reg.getActivePanel()); // force it to activate..
46108 reg.setActivePanel(reg.getActivePanel());
46111 if (!reg.panels.length) {
46114 reg.showPanel(reg.getPanel(0));
46123 * Returns the nested BorderLayout for this panel
46124 * @return {Roo.BorderLayout}
46126 getLayout : function(){
46127 return this.layout;
46131 * Adds a xtype elements to the layout of the nested panel
46135 xtype : 'ContentPanel',
46142 xtype : 'NestedLayoutPanel',
46148 items : [ ... list of content panels or nested layout panels.. ]
46152 * @param {Object} cfg Xtype definition of item to add.
46154 addxtype : function(cfg) {
46155 return this.layout.addxtype(cfg);
46160 Roo.ScrollPanel = function(el, config, content){
46161 config = config || {};
46162 config.fitToFrame = true;
46163 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
46165 this.el.dom.style.overflow = "hidden";
46166 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
46167 this.el.removeClass("x-layout-inactive-content");
46168 this.el.on("mousewheel", this.onWheel, this);
46170 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
46171 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
46172 up.unselectable(); down.unselectable();
46173 up.on("click", this.scrollUp, this);
46174 down.on("click", this.scrollDown, this);
46175 up.addClassOnOver("x-scroller-btn-over");
46176 down.addClassOnOver("x-scroller-btn-over");
46177 up.addClassOnClick("x-scroller-btn-click");
46178 down.addClassOnClick("x-scroller-btn-click");
46179 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
46181 this.resizeEl = this.el;
46182 this.el = wrap; this.up = up; this.down = down;
46185 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
46187 wheelIncrement : 5,
46188 scrollUp : function(){
46189 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
46192 scrollDown : function(){
46193 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
46196 afterScroll : function(){
46197 var el = this.resizeEl;
46198 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
46199 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46200 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46203 setSize : function(){
46204 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
46205 this.afterScroll();
46208 onWheel : function(e){
46209 var d = e.getWheelDelta();
46210 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
46211 this.afterScroll();
46215 setContent : function(content, loadScripts){
46216 this.resizeEl.update(content, loadScripts);
46230 * @class Roo.TreePanel
46231 * @extends Roo.ContentPanel
46233 * Create a new TreePanel. - defaults to fit/scoll contents.
46234 * @param {String/Object} config A string to set only the panel's title, or a config object
46235 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
46237 Roo.TreePanel = function(config){
46238 var el = config.el;
46239 var tree = config.tree;
46240 delete config.tree;
46241 delete config.el; // hopefull!
46243 // wrapper for IE7 strict & safari scroll issue
46245 var treeEl = el.createChild();
46246 config.resizeEl = treeEl;
46250 Roo.TreePanel.superclass.constructor.call(this, el, config);
46253 this.tree = new Roo.tree.TreePanel(treeEl , tree);
46254 //console.log(tree);
46255 this.on('activate', function()
46257 if (this.tree.rendered) {
46260 //console.log('render tree');
46261 this.tree.render();
46264 this.on('resize', function (cp, w, h) {
46265 this.tree.innerCt.setWidth(w);
46266 this.tree.innerCt.setHeight(h);
46267 this.tree.innerCt.setStyle('overflow-y', 'auto');
46274 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46291 * Ext JS Library 1.1.1
46292 * Copyright(c) 2006-2007, Ext JS, LLC.
46294 * Originally Released Under LGPL - original licence link has changed is not relivant.
46297 * <script type="text/javascript">
46302 * @class Roo.ReaderLayout
46303 * @extends Roo.BorderLayout
46304 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46305 * center region containing two nested regions (a top one for a list view and one for item preview below),
46306 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46307 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46308 * expedites the setup of the overall layout and regions for this common application style.
46311 var reader = new Roo.ReaderLayout();
46312 var CP = Roo.ContentPanel; // shortcut for adding
46314 reader.beginUpdate();
46315 reader.add("north", new CP("north", "North"));
46316 reader.add("west", new CP("west", {title: "West"}));
46317 reader.add("east", new CP("east", {title: "East"}));
46319 reader.regions.listView.add(new CP("listView", "List"));
46320 reader.regions.preview.add(new CP("preview", "Preview"));
46321 reader.endUpdate();
46324 * Create a new ReaderLayout
46325 * @param {Object} config Configuration options
46326 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46327 * document.body if omitted)
46329 Roo.ReaderLayout = function(config, renderTo){
46330 var c = config || {size:{}};
46331 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46332 north: c.north !== false ? Roo.apply({
46336 }, c.north) : false,
46337 west: c.west !== false ? Roo.apply({
46345 margins:{left:5,right:0,bottom:5,top:5},
46346 cmargins:{left:5,right:5,bottom:5,top:5}
46347 }, c.west) : false,
46348 east: c.east !== false ? Roo.apply({
46356 margins:{left:0,right:5,bottom:5,top:5},
46357 cmargins:{left:5,right:5,bottom:5,top:5}
46358 }, c.east) : false,
46359 center: Roo.apply({
46360 tabPosition: 'top',
46364 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46368 this.el.addClass('x-reader');
46370 this.beginUpdate();
46372 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46373 south: c.preview !== false ? Roo.apply({
46380 cmargins:{top:5,left:0, right:0, bottom:0}
46381 }, c.preview) : false,
46382 center: Roo.apply({
46388 this.add('center', new Roo.NestedLayoutPanel(inner,
46389 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46393 this.regions.preview = inner.getRegion('south');
46394 this.regions.listView = inner.getRegion('center');
46397 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46399 * Ext JS Library 1.1.1
46400 * Copyright(c) 2006-2007, Ext JS, LLC.
46402 * Originally Released Under LGPL - original licence link has changed is not relivant.
46405 * <script type="text/javascript">
46409 * @class Roo.grid.Grid
46410 * @extends Roo.util.Observable
46411 * This class represents the primary interface of a component based grid control.
46412 * <br><br>Usage:<pre><code>
46413 var grid = new Roo.grid.Grid("my-container-id", {
46416 selModel: mySelectionModel,
46417 autoSizeColumns: true,
46418 monitorWindowResize: false,
46419 trackMouseOver: true
46424 * <b>Common Problems:</b><br/>
46425 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46426 * element will correct this<br/>
46427 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46428 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46429 * are unpredictable.<br/>
46430 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46431 * grid to calculate dimensions/offsets.<br/>
46433 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46434 * The container MUST have some type of size defined for the grid to fill. The container will be
46435 * automatically set to position relative if it isn't already.
46436 * @param {Object} config A config object that sets properties on this grid.
46438 Roo.grid.Grid = function(container, config){
46439 // initialize the container
46440 this.container = Roo.get(container);
46441 this.container.update("");
46442 this.container.setStyle("overflow", "hidden");
46443 this.container.addClass('x-grid-container');
46445 this.id = this.container.id;
46447 Roo.apply(this, config);
46448 // check and correct shorthanded configs
46450 this.dataSource = this.ds;
46454 this.colModel = this.cm;
46458 this.selModel = this.sm;
46462 if (this.selModel) {
46463 this.selModel = Roo.factory(this.selModel, Roo.grid);
46464 this.sm = this.selModel;
46465 this.sm.xmodule = this.xmodule || false;
46467 if (typeof(this.colModel.config) == 'undefined') {
46468 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46469 this.cm = this.colModel;
46470 this.cm.xmodule = this.xmodule || false;
46472 if (this.dataSource) {
46473 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46474 this.ds = this.dataSource;
46475 this.ds.xmodule = this.xmodule || false;
46482 this.container.setWidth(this.width);
46486 this.container.setHeight(this.height);
46493 * The raw click event for the entire grid.
46494 * @param {Roo.EventObject} e
46499 * The raw dblclick event for the entire grid.
46500 * @param {Roo.EventObject} e
46504 * @event contextmenu
46505 * The raw contextmenu event for the entire grid.
46506 * @param {Roo.EventObject} e
46508 "contextmenu" : true,
46511 * The raw mousedown event for the entire grid.
46512 * @param {Roo.EventObject} e
46514 "mousedown" : true,
46517 * The raw mouseup event for the entire grid.
46518 * @param {Roo.EventObject} e
46523 * The raw mouseover event for the entire grid.
46524 * @param {Roo.EventObject} e
46526 "mouseover" : true,
46529 * The raw mouseout event for the entire grid.
46530 * @param {Roo.EventObject} e
46535 * The raw keypress event for the entire grid.
46536 * @param {Roo.EventObject} e
46541 * The raw keydown event for the entire grid.
46542 * @param {Roo.EventObject} e
46550 * Fires when a cell is clicked
46551 * @param {Grid} this
46552 * @param {Number} rowIndex
46553 * @param {Number} columnIndex
46554 * @param {Roo.EventObject} e
46556 "cellclick" : true,
46558 * @event celldblclick
46559 * Fires when a cell is double clicked
46560 * @param {Grid} this
46561 * @param {Number} rowIndex
46562 * @param {Number} columnIndex
46563 * @param {Roo.EventObject} e
46565 "celldblclick" : true,
46568 * Fires when a row is clicked
46569 * @param {Grid} this
46570 * @param {Number} rowIndex
46571 * @param {Roo.EventObject} e
46575 * @event rowdblclick
46576 * Fires when a row is double clicked
46577 * @param {Grid} this
46578 * @param {Number} rowIndex
46579 * @param {Roo.EventObject} e
46581 "rowdblclick" : true,
46583 * @event headerclick
46584 * Fires when a header is clicked
46585 * @param {Grid} this
46586 * @param {Number} columnIndex
46587 * @param {Roo.EventObject} e
46589 "headerclick" : true,
46591 * @event headerdblclick
46592 * Fires when a header cell is double clicked
46593 * @param {Grid} this
46594 * @param {Number} columnIndex
46595 * @param {Roo.EventObject} e
46597 "headerdblclick" : true,
46599 * @event rowcontextmenu
46600 * Fires when a row is right clicked
46601 * @param {Grid} this
46602 * @param {Number} rowIndex
46603 * @param {Roo.EventObject} e
46605 "rowcontextmenu" : true,
46607 * @event cellcontextmenu
46608 * Fires when a cell is right clicked
46609 * @param {Grid} this
46610 * @param {Number} rowIndex
46611 * @param {Number} cellIndex
46612 * @param {Roo.EventObject} e
46614 "cellcontextmenu" : true,
46616 * @event headercontextmenu
46617 * Fires when a header is right clicked
46618 * @param {Grid} this
46619 * @param {Number} columnIndex
46620 * @param {Roo.EventObject} e
46622 "headercontextmenu" : true,
46624 * @event bodyscroll
46625 * Fires when the body element is scrolled
46626 * @param {Number} scrollLeft
46627 * @param {Number} scrollTop
46629 "bodyscroll" : true,
46631 * @event columnresize
46632 * Fires when the user resizes a column
46633 * @param {Number} columnIndex
46634 * @param {Number} newSize
46636 "columnresize" : true,
46638 * @event columnmove
46639 * Fires when the user moves a column
46640 * @param {Number} oldIndex
46641 * @param {Number} newIndex
46643 "columnmove" : true,
46646 * Fires when row(s) start being dragged
46647 * @param {Grid} this
46648 * @param {Roo.GridDD} dd The drag drop object
46649 * @param {event} e The raw browser event
46651 "startdrag" : true,
46654 * Fires when a drag operation is complete
46655 * @param {Grid} this
46656 * @param {Roo.GridDD} dd The drag drop object
46657 * @param {event} e The raw browser event
46662 * Fires when dragged row(s) are dropped on a valid DD target
46663 * @param {Grid} this
46664 * @param {Roo.GridDD} dd The drag drop object
46665 * @param {String} targetId The target drag drop object
46666 * @param {event} e The raw browser event
46671 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46672 * @param {Grid} this
46673 * @param {Roo.GridDD} dd The drag drop object
46674 * @param {String} targetId The target drag drop object
46675 * @param {event} e The raw browser event
46680 * Fires when the dragged row(s) first cross another DD target while being dragged
46681 * @param {Grid} this
46682 * @param {Roo.GridDD} dd The drag drop object
46683 * @param {String} targetId The target drag drop object
46684 * @param {event} e The raw browser event
46686 "dragenter" : true,
46689 * Fires when the dragged row(s) leave another DD target while being dragged
46690 * @param {Grid} this
46691 * @param {Roo.GridDD} dd The drag drop object
46692 * @param {String} targetId The target drag drop object
46693 * @param {event} e The raw browser event
46698 * Fires when a row is rendered, so you can change add a style to it.
46699 * @param {GridView} gridview The grid view
46700 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
46706 * Fires when the grid is rendered
46707 * @param {Grid} grid
46712 Roo.grid.Grid.superclass.constructor.call(this);
46714 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46717 * @cfg {String} ddGroup - drag drop group.
46721 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46723 minColumnWidth : 25,
46726 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46727 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46728 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46730 autoSizeColumns : false,
46733 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46735 autoSizeHeaders : true,
46738 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46740 monitorWindowResize : true,
46743 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46744 * rows measured to get a columns size. Default is 0 (all rows).
46746 maxRowsToMeasure : 0,
46749 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46751 trackMouseOver : true,
46754 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46758 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46760 enableDragDrop : false,
46763 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46765 enableColumnMove : true,
46768 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46770 enableColumnHide : true,
46773 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46775 enableRowHeightSync : false,
46778 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46783 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46785 autoHeight : false,
46788 * @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.
46790 autoExpandColumn : false,
46793 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46796 autoExpandMin : 50,
46799 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46801 autoExpandMax : 1000,
46804 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46809 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46813 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46823 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46824 * of a fixed width. Default is false.
46827 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46830 * Called once after all setup has been completed and the grid is ready to be rendered.
46831 * @return {Roo.grid.Grid} this
46833 render : function()
46835 var c = this.container;
46836 // try to detect autoHeight/width mode
46837 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46838 this.autoHeight = true;
46840 var view = this.getView();
46843 c.on("click", this.onClick, this);
46844 c.on("dblclick", this.onDblClick, this);
46845 c.on("contextmenu", this.onContextMenu, this);
46846 c.on("keydown", this.onKeyDown, this);
46848 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46850 this.getSelectionModel().init(this);
46855 this.loadMask = new Roo.LoadMask(this.container,
46856 Roo.apply({store:this.dataSource}, this.loadMask));
46860 if (this.toolbar && this.toolbar.xtype) {
46861 this.toolbar.container = this.getView().getHeaderPanel(true);
46862 this.toolbar = new Roo.Toolbar(this.toolbar);
46864 if (this.footer && this.footer.xtype) {
46865 this.footer.dataSource = this.getDataSource();
46866 this.footer.container = this.getView().getFooterPanel(true);
46867 this.footer = Roo.factory(this.footer, Roo);
46869 if (this.dropTarget && this.dropTarget.xtype) {
46870 delete this.dropTarget.xtype;
46871 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46875 this.rendered = true;
46876 this.fireEvent('render', this);
46881 * Reconfigures the grid to use a different Store and Column Model.
46882 * The View will be bound to the new objects and refreshed.
46883 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46884 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46886 reconfigure : function(dataSource, colModel){
46888 this.loadMask.destroy();
46889 this.loadMask = new Roo.LoadMask(this.container,
46890 Roo.apply({store:dataSource}, this.loadMask));
46892 this.view.bind(dataSource, colModel);
46893 this.dataSource = dataSource;
46894 this.colModel = colModel;
46895 this.view.refresh(true);
46899 onKeyDown : function(e){
46900 this.fireEvent("keydown", e);
46904 * Destroy this grid.
46905 * @param {Boolean} removeEl True to remove the element
46907 destroy : function(removeEl, keepListeners){
46909 this.loadMask.destroy();
46911 var c = this.container;
46912 c.removeAllListeners();
46913 this.view.destroy();
46914 this.colModel.purgeListeners();
46915 if(!keepListeners){
46916 this.purgeListeners();
46919 if(removeEl === true){
46925 processEvent : function(name, e){
46926 this.fireEvent(name, e);
46927 var t = e.getTarget();
46929 var header = v.findHeaderIndex(t);
46930 if(header !== false){
46931 this.fireEvent("header" + name, this, header, e);
46933 var row = v.findRowIndex(t);
46934 var cell = v.findCellIndex(t);
46936 this.fireEvent("row" + name, this, row, e);
46937 if(cell !== false){
46938 this.fireEvent("cell" + name, this, row, cell, e);
46945 onClick : function(e){
46946 this.processEvent("click", e);
46950 onContextMenu : function(e, t){
46951 this.processEvent("contextmenu", e);
46955 onDblClick : function(e){
46956 this.processEvent("dblclick", e);
46960 walkCells : function(row, col, step, fn, scope){
46961 var cm = this.colModel, clen = cm.getColumnCount();
46962 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46974 if(fn.call(scope || this, row, col, cm) === true){
46992 if(fn.call(scope || this, row, col, cm) === true){
47004 getSelections : function(){
47005 return this.selModel.getSelections();
47009 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47010 * but if manual update is required this method will initiate it.
47012 autoSize : function(){
47014 this.view.layout();
47015 if(this.view.adjustForScroll){
47016 this.view.adjustForScroll();
47022 * Returns the grid's underlying element.
47023 * @return {Element} The element
47025 getGridEl : function(){
47026 return this.container;
47029 // private for compatibility, overridden by editor grid
47030 stopEditing : function(){},
47033 * Returns the grid's SelectionModel.
47034 * @return {SelectionModel}
47036 getSelectionModel : function(){
47037 if(!this.selModel){
47038 this.selModel = new Roo.grid.RowSelectionModel();
47040 return this.selModel;
47044 * Returns the grid's DataSource.
47045 * @return {DataSource}
47047 getDataSource : function(){
47048 return this.dataSource;
47052 * Returns the grid's ColumnModel.
47053 * @return {ColumnModel}
47055 getColumnModel : function(){
47056 return this.colModel;
47060 * Returns the grid's GridView object.
47061 * @return {GridView}
47063 getView : function(){
47065 this.view = new Roo.grid.GridView(this.viewConfig);
47070 * Called to get grid's drag proxy text, by default returns this.ddText.
47073 getDragDropText : function(){
47074 var count = this.selModel.getCount();
47075 return String.format(this.ddText, count, count == 1 ? '' : 's');
47079 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
47080 * %0 is replaced with the number of selected rows.
47083 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
47085 * Ext JS Library 1.1.1
47086 * Copyright(c) 2006-2007, Ext JS, LLC.
47088 * Originally Released Under LGPL - original licence link has changed is not relivant.
47091 * <script type="text/javascript">
47094 Roo.grid.AbstractGridView = function(){
47098 "beforerowremoved" : true,
47099 "beforerowsinserted" : true,
47100 "beforerefresh" : true,
47101 "rowremoved" : true,
47102 "rowsinserted" : true,
47103 "rowupdated" : true,
47106 Roo.grid.AbstractGridView.superclass.constructor.call(this);
47109 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
47110 rowClass : "x-grid-row",
47111 cellClass : "x-grid-cell",
47112 tdClass : "x-grid-td",
47113 hdClass : "x-grid-hd",
47114 splitClass : "x-grid-hd-split",
47116 init: function(grid){
47118 var cid = this.grid.getGridEl().id;
47119 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
47120 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
47121 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
47122 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
47125 getColumnRenderers : function(){
47126 var renderers = [];
47127 var cm = this.grid.colModel;
47128 var colCount = cm.getColumnCount();
47129 for(var i = 0; i < colCount; i++){
47130 renderers[i] = cm.getRenderer(i);
47135 getColumnIds : function(){
47137 var cm = this.grid.colModel;
47138 var colCount = cm.getColumnCount();
47139 for(var i = 0; i < colCount; i++){
47140 ids[i] = cm.getColumnId(i);
47145 getDataIndexes : function(){
47146 if(!this.indexMap){
47147 this.indexMap = this.buildIndexMap();
47149 return this.indexMap.colToData;
47152 getColumnIndexByDataIndex : function(dataIndex){
47153 if(!this.indexMap){
47154 this.indexMap = this.buildIndexMap();
47156 return this.indexMap.dataToCol[dataIndex];
47160 * Set a css style for a column dynamically.
47161 * @param {Number} colIndex The index of the column
47162 * @param {String} name The css property name
47163 * @param {String} value The css value
47165 setCSSStyle : function(colIndex, name, value){
47166 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
47167 Roo.util.CSS.updateRule(selector, name, value);
47170 generateRules : function(cm){
47171 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
47172 Roo.util.CSS.removeStyleSheet(rulesId);
47173 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47174 var cid = cm.getColumnId(i);
47175 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
47176 this.tdSelector, cid, " {\n}\n",
47177 this.hdSelector, cid, " {\n}\n",
47178 this.splitSelector, cid, " {\n}\n");
47180 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47184 * Ext JS Library 1.1.1
47185 * Copyright(c) 2006-2007, Ext JS, LLC.
47187 * Originally Released Under LGPL - original licence link has changed is not relivant.
47190 * <script type="text/javascript">
47194 // This is a support class used internally by the Grid components
47195 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
47197 this.view = grid.getView();
47198 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47199 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
47201 this.setHandleElId(Roo.id(hd));
47202 this.setOuterHandleElId(Roo.id(hd2));
47204 this.scroll = false;
47206 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
47208 getDragData : function(e){
47209 var t = Roo.lib.Event.getTarget(e);
47210 var h = this.view.findHeaderCell(t);
47212 return {ddel: h.firstChild, header:h};
47217 onInitDrag : function(e){
47218 this.view.headersDisabled = true;
47219 var clone = this.dragData.ddel.cloneNode(true);
47220 clone.id = Roo.id();
47221 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
47222 this.proxy.update(clone);
47226 afterValidDrop : function(){
47228 setTimeout(function(){
47229 v.headersDisabled = false;
47233 afterInvalidDrop : function(){
47235 setTimeout(function(){
47236 v.headersDisabled = false;
47242 * Ext JS Library 1.1.1
47243 * Copyright(c) 2006-2007, Ext JS, LLC.
47245 * Originally Released Under LGPL - original licence link has changed is not relivant.
47248 * <script type="text/javascript">
47251 // This is a support class used internally by the Grid components
47252 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
47254 this.view = grid.getView();
47255 // split the proxies so they don't interfere with mouse events
47256 this.proxyTop = Roo.DomHelper.append(document.body, {
47257 cls:"col-move-top", html:" "
47259 this.proxyBottom = Roo.DomHelper.append(document.body, {
47260 cls:"col-move-bottom", html:" "
47262 this.proxyTop.hide = this.proxyBottom.hide = function(){
47263 this.setLeftTop(-100,-100);
47264 this.setStyle("visibility", "hidden");
47266 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47267 // temporarily disabled
47268 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47269 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47271 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47272 proxyOffsets : [-4, -9],
47273 fly: Roo.Element.fly,
47275 getTargetFromEvent : function(e){
47276 var t = Roo.lib.Event.getTarget(e);
47277 var cindex = this.view.findCellIndex(t);
47278 if(cindex !== false){
47279 return this.view.getHeaderCell(cindex);
47284 nextVisible : function(h){
47285 var v = this.view, cm = this.grid.colModel;
47288 if(!cm.isHidden(v.getCellIndex(h))){
47296 prevVisible : function(h){
47297 var v = this.view, cm = this.grid.colModel;
47300 if(!cm.isHidden(v.getCellIndex(h))){
47308 positionIndicator : function(h, n, e){
47309 var x = Roo.lib.Event.getPageX(e);
47310 var r = Roo.lib.Dom.getRegion(n.firstChild);
47311 var px, pt, py = r.top + this.proxyOffsets[1];
47312 if((r.right - x) <= (r.right-r.left)/2){
47313 px = r.right+this.view.borderWidth;
47319 var oldIndex = this.view.getCellIndex(h);
47320 var newIndex = this.view.getCellIndex(n);
47322 if(this.grid.colModel.isFixed(newIndex)){
47326 var locked = this.grid.colModel.isLocked(newIndex);
47331 if(oldIndex < newIndex){
47334 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47337 px += this.proxyOffsets[0];
47338 this.proxyTop.setLeftTop(px, py);
47339 this.proxyTop.show();
47340 if(!this.bottomOffset){
47341 this.bottomOffset = this.view.mainHd.getHeight();
47343 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47344 this.proxyBottom.show();
47348 onNodeEnter : function(n, dd, e, data){
47349 if(data.header != n){
47350 this.positionIndicator(data.header, n, e);
47354 onNodeOver : function(n, dd, e, data){
47355 var result = false;
47356 if(data.header != n){
47357 result = this.positionIndicator(data.header, n, e);
47360 this.proxyTop.hide();
47361 this.proxyBottom.hide();
47363 return result ? this.dropAllowed : this.dropNotAllowed;
47366 onNodeOut : function(n, dd, e, data){
47367 this.proxyTop.hide();
47368 this.proxyBottom.hide();
47371 onNodeDrop : function(n, dd, e, data){
47372 var h = data.header;
47374 var cm = this.grid.colModel;
47375 var x = Roo.lib.Event.getPageX(e);
47376 var r = Roo.lib.Dom.getRegion(n.firstChild);
47377 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47378 var oldIndex = this.view.getCellIndex(h);
47379 var newIndex = this.view.getCellIndex(n);
47380 var locked = cm.isLocked(newIndex);
47384 if(oldIndex < newIndex){
47387 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47390 cm.setLocked(oldIndex, locked, true);
47391 cm.moveColumn(oldIndex, newIndex);
47392 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47400 * Ext JS Library 1.1.1
47401 * Copyright(c) 2006-2007, Ext JS, LLC.
47403 * Originally Released Under LGPL - original licence link has changed is not relivant.
47406 * <script type="text/javascript">
47410 * @class Roo.grid.GridView
47411 * @extends Roo.util.Observable
47414 * @param {Object} config
47416 Roo.grid.GridView = function(config){
47417 Roo.grid.GridView.superclass.constructor.call(this);
47420 Roo.apply(this, config);
47423 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47426 * Override this function to apply custom css classes to rows during rendering
47427 * @param {Record} record The record
47428 * @param {Number} index
47429 * @method getRowClass
47431 rowClass : "x-grid-row",
47433 cellClass : "x-grid-col",
47435 tdClass : "x-grid-td",
47437 hdClass : "x-grid-hd",
47439 splitClass : "x-grid-split",
47441 sortClasses : ["sort-asc", "sort-desc"],
47443 enableMoveAnim : false,
47447 dh : Roo.DomHelper,
47449 fly : Roo.Element.fly,
47451 css : Roo.util.CSS,
47457 scrollIncrement : 22,
47459 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47461 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47463 bind : function(ds, cm){
47465 this.ds.un("load", this.onLoad, this);
47466 this.ds.un("datachanged", this.onDataChange, this);
47467 this.ds.un("add", this.onAdd, this);
47468 this.ds.un("remove", this.onRemove, this);
47469 this.ds.un("update", this.onUpdate, this);
47470 this.ds.un("clear", this.onClear, this);
47473 ds.on("load", this.onLoad, this);
47474 ds.on("datachanged", this.onDataChange, this);
47475 ds.on("add", this.onAdd, this);
47476 ds.on("remove", this.onRemove, this);
47477 ds.on("update", this.onUpdate, this);
47478 ds.on("clear", this.onClear, this);
47483 this.cm.un("widthchange", this.onColWidthChange, this);
47484 this.cm.un("headerchange", this.onHeaderChange, this);
47485 this.cm.un("hiddenchange", this.onHiddenChange, this);
47486 this.cm.un("columnmoved", this.onColumnMove, this);
47487 this.cm.un("columnlockchange", this.onColumnLock, this);
47490 this.generateRules(cm);
47491 cm.on("widthchange", this.onColWidthChange, this);
47492 cm.on("headerchange", this.onHeaderChange, this);
47493 cm.on("hiddenchange", this.onHiddenChange, this);
47494 cm.on("columnmoved", this.onColumnMove, this);
47495 cm.on("columnlockchange", this.onColumnLock, this);
47500 init: function(grid){
47501 Roo.grid.GridView.superclass.init.call(this, grid);
47503 this.bind(grid.dataSource, grid.colModel);
47505 grid.on("headerclick", this.handleHeaderClick, this);
47507 if(grid.trackMouseOver){
47508 grid.on("mouseover", this.onRowOver, this);
47509 grid.on("mouseout", this.onRowOut, this);
47511 grid.cancelTextSelection = function(){};
47512 this.gridId = grid.id;
47514 var tpls = this.templates || {};
47517 tpls.master = new Roo.Template(
47518 '<div class="x-grid" hidefocus="true">',
47519 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47520 '<div class="x-grid-topbar"></div>',
47521 '<div class="x-grid-scroller"><div></div></div>',
47522 '<div class="x-grid-locked">',
47523 '<div class="x-grid-header">{lockedHeader}</div>',
47524 '<div class="x-grid-body">{lockedBody}</div>',
47526 '<div class="x-grid-viewport">',
47527 '<div class="x-grid-header">{header}</div>',
47528 '<div class="x-grid-body">{body}</div>',
47530 '<div class="x-grid-bottombar"></div>',
47532 '<div class="x-grid-resize-proxy"> </div>',
47535 tpls.master.disableformats = true;
47539 tpls.header = new Roo.Template(
47540 '<table border="0" cellspacing="0" cellpadding="0">',
47541 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47544 tpls.header.disableformats = true;
47546 tpls.header.compile();
47549 tpls.hcell = new Roo.Template(
47550 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47551 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47554 tpls.hcell.disableFormats = true;
47556 tpls.hcell.compile();
47559 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47560 tpls.hsplit.disableFormats = true;
47562 tpls.hsplit.compile();
47565 tpls.body = new Roo.Template(
47566 '<table border="0" cellspacing="0" cellpadding="0">',
47567 "<tbody>{rows}</tbody>",
47570 tpls.body.disableFormats = true;
47572 tpls.body.compile();
47575 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47576 tpls.row.disableFormats = true;
47578 tpls.row.compile();
47581 tpls.cell = new Roo.Template(
47582 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47583 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47586 tpls.cell.disableFormats = true;
47588 tpls.cell.compile();
47590 this.templates = tpls;
47593 // remap these for backwards compat
47594 onColWidthChange : function(){
47595 this.updateColumns.apply(this, arguments);
47597 onHeaderChange : function(){
47598 this.updateHeaders.apply(this, arguments);
47600 onHiddenChange : function(){
47601 this.handleHiddenChange.apply(this, arguments);
47603 onColumnMove : function(){
47604 this.handleColumnMove.apply(this, arguments);
47606 onColumnLock : function(){
47607 this.handleLockChange.apply(this, arguments);
47610 onDataChange : function(){
47612 this.updateHeaderSortState();
47615 onClear : function(){
47619 onUpdate : function(ds, record){
47620 this.refreshRow(record);
47623 refreshRow : function(record){
47624 var ds = this.ds, index;
47625 if(typeof record == 'number'){
47627 record = ds.getAt(index);
47629 index = ds.indexOf(record);
47631 this.insertRows(ds, index, index, true);
47632 this.onRemove(ds, record, index+1, true);
47633 this.syncRowHeights(index, index);
47635 this.fireEvent("rowupdated", this, index, record);
47638 onAdd : function(ds, records, index){
47639 this.insertRows(ds, index, index + (records.length-1));
47642 onRemove : function(ds, record, index, isUpdate){
47643 if(isUpdate !== true){
47644 this.fireEvent("beforerowremoved", this, index, record);
47646 var bt = this.getBodyTable(), lt = this.getLockedTable();
47647 if(bt.rows[index]){
47648 bt.firstChild.removeChild(bt.rows[index]);
47650 if(lt.rows[index]){
47651 lt.firstChild.removeChild(lt.rows[index]);
47653 if(isUpdate !== true){
47654 this.stripeRows(index);
47655 this.syncRowHeights(index, index);
47657 this.fireEvent("rowremoved", this, index, record);
47661 onLoad : function(){
47662 this.scrollToTop();
47666 * Scrolls the grid to the top
47668 scrollToTop : function(){
47670 this.scroller.dom.scrollTop = 0;
47676 * Gets a panel in the header of the grid that can be used for toolbars etc.
47677 * After modifying the contents of this panel a call to grid.autoSize() may be
47678 * required to register any changes in size.
47679 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47680 * @return Roo.Element
47682 getHeaderPanel : function(doShow){
47684 this.headerPanel.show();
47686 return this.headerPanel;
47690 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47691 * After modifying the contents of this panel a call to grid.autoSize() may be
47692 * required to register any changes in size.
47693 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47694 * @return Roo.Element
47696 getFooterPanel : function(doShow){
47698 this.footerPanel.show();
47700 return this.footerPanel;
47703 initElements : function(){
47704 var E = Roo.Element;
47705 var el = this.grid.getGridEl().dom.firstChild;
47706 var cs = el.childNodes;
47708 this.el = new E(el);
47710 this.focusEl = new E(el.firstChild);
47711 this.focusEl.swallowEvent("click", true);
47713 this.headerPanel = new E(cs[1]);
47714 this.headerPanel.enableDisplayMode("block");
47716 this.scroller = new E(cs[2]);
47717 this.scrollSizer = new E(this.scroller.dom.firstChild);
47719 this.lockedWrap = new E(cs[3]);
47720 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47721 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47723 this.mainWrap = new E(cs[4]);
47724 this.mainHd = new E(this.mainWrap.dom.firstChild);
47725 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47727 this.footerPanel = new E(cs[5]);
47728 this.footerPanel.enableDisplayMode("block");
47730 this.resizeProxy = new E(cs[6]);
47732 this.headerSelector = String.format(
47733 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47734 this.lockedHd.id, this.mainHd.id
47737 this.splitterSelector = String.format(
47738 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47739 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47742 idToCssName : function(s)
47744 return s.replace(/[^a-z0-9]+/ig, '-');
47747 getHeaderCell : function(index){
47748 return Roo.DomQuery.select(this.headerSelector)[index];
47751 getHeaderCellMeasure : function(index){
47752 return this.getHeaderCell(index).firstChild;
47755 getHeaderCellText : function(index){
47756 return this.getHeaderCell(index).firstChild.firstChild;
47759 getLockedTable : function(){
47760 return this.lockedBody.dom.firstChild;
47763 getBodyTable : function(){
47764 return this.mainBody.dom.firstChild;
47767 getLockedRow : function(index){
47768 return this.getLockedTable().rows[index];
47771 getRow : function(index){
47772 return this.getBodyTable().rows[index];
47775 getRowComposite : function(index){
47777 this.rowEl = new Roo.CompositeElementLite();
47779 var els = [], lrow, mrow;
47780 if(lrow = this.getLockedRow(index)){
47783 if(mrow = this.getRow(index)){
47786 this.rowEl.elements = els;
47790 getCell : function(rowIndex, colIndex){
47791 var locked = this.cm.getLockedCount();
47793 if(colIndex < locked){
47794 source = this.lockedBody.dom.firstChild;
47796 source = this.mainBody.dom.firstChild;
47797 colIndex -= locked;
47799 return source.rows[rowIndex].childNodes[colIndex];
47802 getCellText : function(rowIndex, colIndex){
47803 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47806 getCellBox : function(cell){
47807 var b = this.fly(cell).getBox();
47808 if(Roo.isOpera){ // opera fails to report the Y
47809 b.y = cell.offsetTop + this.mainBody.getY();
47814 getCellIndex : function(cell){
47815 var id = String(cell.className).match(this.cellRE);
47817 return parseInt(id[1], 10);
47822 findHeaderIndex : function(n){
47823 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47824 return r ? this.getCellIndex(r) : false;
47827 findHeaderCell : function(n){
47828 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47829 return r ? r : false;
47832 findRowIndex : function(n){
47836 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47837 return r ? r.rowIndex : false;
47840 findCellIndex : function(node){
47841 var stop = this.el.dom;
47842 while(node && node != stop){
47843 if(this.findRE.test(node.className)){
47844 return this.getCellIndex(node);
47846 node = node.parentNode;
47851 getColumnId : function(index){
47852 return this.cm.getColumnId(index);
47855 getSplitters : function()
47857 if(this.splitterSelector){
47858 return Roo.DomQuery.select(this.splitterSelector);
47864 getSplitter : function(index){
47865 return this.getSplitters()[index];
47868 onRowOver : function(e, t){
47870 if((row = this.findRowIndex(t)) !== false){
47871 this.getRowComposite(row).addClass("x-grid-row-over");
47875 onRowOut : function(e, t){
47877 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47878 this.getRowComposite(row).removeClass("x-grid-row-over");
47882 renderHeaders : function(){
47884 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47885 var cb = [], lb = [], sb = [], lsb = [], p = {};
47886 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47887 p.cellId = "x-grid-hd-0-" + i;
47888 p.splitId = "x-grid-csplit-0-" + i;
47889 p.id = cm.getColumnId(i);
47890 p.title = cm.getColumnTooltip(i) || "";
47891 p.value = cm.getColumnHeader(i) || "";
47892 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47893 if(!cm.isLocked(i)){
47894 cb[cb.length] = ct.apply(p);
47895 sb[sb.length] = st.apply(p);
47897 lb[lb.length] = ct.apply(p);
47898 lsb[lsb.length] = st.apply(p);
47901 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47902 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47905 updateHeaders : function(){
47906 var html = this.renderHeaders();
47907 this.lockedHd.update(html[0]);
47908 this.mainHd.update(html[1]);
47912 * Focuses the specified row.
47913 * @param {Number} row The row index
47915 focusRow : function(row)
47917 //Roo.log('GridView.focusRow');
47918 var x = this.scroller.dom.scrollLeft;
47919 this.focusCell(row, 0, false);
47920 this.scroller.dom.scrollLeft = x;
47924 * Focuses the specified cell.
47925 * @param {Number} row The row index
47926 * @param {Number} col The column index
47927 * @param {Boolean} hscroll false to disable horizontal scrolling
47929 focusCell : function(row, col, hscroll)
47931 //Roo.log('GridView.focusCell');
47932 var el = this.ensureVisible(row, col, hscroll);
47933 this.focusEl.alignTo(el, "tl-tl");
47935 this.focusEl.focus();
47937 this.focusEl.focus.defer(1, this.focusEl);
47942 * Scrolls the specified cell into view
47943 * @param {Number} row The row index
47944 * @param {Number} col The column index
47945 * @param {Boolean} hscroll false to disable horizontal scrolling
47947 ensureVisible : function(row, col, hscroll)
47949 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
47950 //return null; //disable for testing.
47951 if(typeof row != "number"){
47952 row = row.rowIndex;
47954 if(row < 0 && row >= this.ds.getCount()){
47957 col = (col !== undefined ? col : 0);
47958 var cm = this.grid.colModel;
47959 while(cm.isHidden(col)){
47963 var el = this.getCell(row, col);
47967 var c = this.scroller.dom;
47969 var ctop = parseInt(el.offsetTop, 10);
47970 var cleft = parseInt(el.offsetLeft, 10);
47971 var cbot = ctop + el.offsetHeight;
47972 var cright = cleft + el.offsetWidth;
47974 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47975 var stop = parseInt(c.scrollTop, 10);
47976 var sleft = parseInt(c.scrollLeft, 10);
47977 var sbot = stop + ch;
47978 var sright = sleft + c.clientWidth;
47980 Roo.log('GridView.ensureVisible:' +
47982 ' c.clientHeight:' + c.clientHeight +
47983 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
47991 c.scrollTop = ctop;
47992 //Roo.log("set scrolltop to ctop DISABLE?");
47993 }else if(cbot > sbot){
47994 //Roo.log("set scrolltop to cbot-ch");
47995 c.scrollTop = cbot-ch;
47998 if(hscroll !== false){
48000 c.scrollLeft = cleft;
48001 }else if(cright > sright){
48002 c.scrollLeft = cright-c.clientWidth;
48009 updateColumns : function(){
48010 this.grid.stopEditing();
48011 var cm = this.grid.colModel, colIds = this.getColumnIds();
48012 //var totalWidth = cm.getTotalWidth();
48014 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48015 //if(cm.isHidden(i)) continue;
48016 var w = cm.getColumnWidth(i);
48017 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48018 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48020 this.updateSplitters();
48023 generateRules : function(cm){
48024 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48025 Roo.util.CSS.removeStyleSheet(rulesId);
48026 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48027 var cid = cm.getColumnId(i);
48029 if(cm.config[i].align){
48030 align = 'text-align:'+cm.config[i].align+';';
48033 if(cm.isHidden(i)){
48034 hidden = 'display:none;';
48036 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
48038 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
48039 this.hdSelector, cid, " {\n", align, width, "}\n",
48040 this.tdSelector, cid, " {\n",hidden,"\n}\n",
48041 this.splitSelector, cid, " {\n", hidden , "\n}\n");
48043 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48046 updateSplitters : function(){
48047 var cm = this.cm, s = this.getSplitters();
48048 if(s){ // splitters not created yet
48049 var pos = 0, locked = true;
48050 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48051 if(cm.isHidden(i)) continue;
48052 var w = cm.getColumnWidth(i); // make sure it's a number
48053 if(!cm.isLocked(i) && locked){
48058 s[i].style.left = (pos-this.splitOffset) + "px";
48063 handleHiddenChange : function(colModel, colIndex, hidden){
48065 this.hideColumn(colIndex);
48067 this.unhideColumn(colIndex);
48071 hideColumn : function(colIndex){
48072 var cid = this.getColumnId(colIndex);
48073 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
48074 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
48076 this.updateHeaders();
48078 this.updateSplitters();
48082 unhideColumn : function(colIndex){
48083 var cid = this.getColumnId(colIndex);
48084 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
48085 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
48088 this.updateHeaders();
48090 this.updateSplitters();
48094 insertRows : function(dm, firstRow, lastRow, isUpdate){
48095 if(firstRow == 0 && lastRow == dm.getCount()-1){
48099 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
48101 var s = this.getScrollState();
48102 var markup = this.renderRows(firstRow, lastRow);
48103 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
48104 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
48105 this.restoreScroll(s);
48107 this.fireEvent("rowsinserted", this, firstRow, lastRow);
48108 this.syncRowHeights(firstRow, lastRow);
48109 this.stripeRows(firstRow);
48115 bufferRows : function(markup, target, index){
48116 var before = null, trows = target.rows, tbody = target.tBodies[0];
48117 if(index < trows.length){
48118 before = trows[index];
48120 var b = document.createElement("div");
48121 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
48122 var rows = b.firstChild.rows;
48123 for(var i = 0, len = rows.length; i < len; i++){
48125 tbody.insertBefore(rows[0], before);
48127 tbody.appendChild(rows[0]);
48134 deleteRows : function(dm, firstRow, lastRow){
48135 if(dm.getRowCount()<1){
48136 this.fireEvent("beforerefresh", this);
48137 this.mainBody.update("");
48138 this.lockedBody.update("");
48139 this.fireEvent("refresh", this);
48141 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
48142 var bt = this.getBodyTable();
48143 var tbody = bt.firstChild;
48144 var rows = bt.rows;
48145 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
48146 tbody.removeChild(rows[firstRow]);
48148 this.stripeRows(firstRow);
48149 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
48153 updateRows : function(dataSource, firstRow, lastRow){
48154 var s = this.getScrollState();
48156 this.restoreScroll(s);
48159 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
48163 this.updateHeaderSortState();
48166 getScrollState : function(){
48168 var sb = this.scroller.dom;
48169 return {left: sb.scrollLeft, top: sb.scrollTop};
48172 stripeRows : function(startRow){
48173 if(!this.grid.stripeRows || this.ds.getCount() < 1){
48176 startRow = startRow || 0;
48177 var rows = this.getBodyTable().rows;
48178 var lrows = this.getLockedTable().rows;
48179 var cls = ' x-grid-row-alt ';
48180 for(var i = startRow, len = rows.length; i < len; i++){
48181 var row = rows[i], lrow = lrows[i];
48182 var isAlt = ((i+1) % 2 == 0);
48183 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
48184 if(isAlt == hasAlt){
48188 row.className += " x-grid-row-alt";
48190 row.className = row.className.replace("x-grid-row-alt", "");
48193 lrow.className = row.className;
48198 restoreScroll : function(state){
48199 //Roo.log('GridView.restoreScroll');
48200 var sb = this.scroller.dom;
48201 sb.scrollLeft = state.left;
48202 sb.scrollTop = state.top;
48206 syncScroll : function(){
48207 //Roo.log('GridView.syncScroll');
48208 var sb = this.scroller.dom;
48209 var sh = this.mainHd.dom;
48210 var bs = this.mainBody.dom;
48211 var lv = this.lockedBody.dom;
48212 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
48213 lv.scrollTop = bs.scrollTop = sb.scrollTop;
48216 handleScroll : function(e){
48218 var sb = this.scroller.dom;
48219 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
48223 handleWheel : function(e){
48224 var d = e.getWheelDelta();
48225 this.scroller.dom.scrollTop -= d*22;
48226 // set this here to prevent jumpy scrolling on large tables
48227 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
48231 renderRows : function(startRow, endRow){
48232 // pull in all the crap needed to render rows
48233 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
48234 var colCount = cm.getColumnCount();
48236 if(ds.getCount() < 1){
48240 // build a map for all the columns
48242 for(var i = 0; i < colCount; i++){
48243 var name = cm.getDataIndex(i);
48245 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
48246 renderer : cm.getRenderer(i),
48247 id : cm.getColumnId(i),
48248 locked : cm.isLocked(i)
48252 startRow = startRow || 0;
48253 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
48255 // records to render
48256 var rs = ds.getRange(startRow, endRow);
48258 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
48261 // As much as I hate to duplicate code, this was branched because FireFox really hates
48262 // [].join("") on strings. The performance difference was substantial enough to
48263 // branch this function
48264 doRender : Roo.isGecko ?
48265 function(cs, rs, ds, startRow, colCount, stripe){
48266 var ts = this.templates, ct = ts.cell, rt = ts.row;
48268 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48270 var hasListener = this.grid.hasListener('rowclass');
48272 for(var j = 0, len = rs.length; j < len; j++){
48273 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
48274 for(var i = 0; i < colCount; i++){
48276 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48278 p.css = p.attr = "";
48279 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48280 if(p.value == undefined || p.value === "") p.value = " ";
48281 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48282 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48284 var markup = ct.apply(p);
48292 if(stripe && ((rowIndex+1) % 2 == 0)){
48293 alt.push("x-grid-row-alt")
48296 alt.push( " x-grid-dirty-row");
48299 if(this.getRowClass){
48300 alt.push(this.getRowClass(r, rowIndex));
48306 rowIndex : rowIndex,
48309 this.grid.fireEvent('rowclass', this, rowcfg);
48310 alt.push(rowcfg.rowClass);
48312 rp.alt = alt.join(" ");
48313 lbuf+= rt.apply(rp);
48315 buf+= rt.apply(rp);
48317 return [lbuf, buf];
48319 function(cs, rs, ds, startRow, colCount, stripe){
48320 var ts = this.templates, ct = ts.cell, rt = ts.row;
48322 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48323 var hasListener = this.grid.hasListener('rowclass');
48325 for(var j = 0, len = rs.length; j < len; j++){
48326 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48327 for(var i = 0; i < colCount; i++){
48329 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48331 p.css = p.attr = "";
48332 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48333 if(p.value == undefined || p.value === "") p.value = " ";
48334 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48335 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48337 var markup = ct.apply(p);
48339 cb[cb.length] = markup;
48341 lcb[lcb.length] = markup;
48345 if(stripe && ((rowIndex+1) % 2 == 0)){
48346 alt.push( "x-grid-row-alt");
48349 alt.push(" x-grid-dirty-row");
48352 if(this.getRowClass){
48353 alt.push( this.getRowClass(r, rowIndex));
48359 rowIndex : rowIndex,
48362 this.grid.fireEvent('rowclass', this, rowcfg);
48363 alt.push(rowcfg.rowClass);
48365 rp.alt = alt.join(" ");
48366 rp.cells = lcb.join("");
48367 lbuf[lbuf.length] = rt.apply(rp);
48368 rp.cells = cb.join("");
48369 buf[buf.length] = rt.apply(rp);
48371 return [lbuf.join(""), buf.join("")];
48374 renderBody : function(){
48375 var markup = this.renderRows();
48376 var bt = this.templates.body;
48377 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48381 * Refreshes the grid
48382 * @param {Boolean} headersToo
48384 refresh : function(headersToo){
48385 this.fireEvent("beforerefresh", this);
48386 this.grid.stopEditing();
48387 var result = this.renderBody();
48388 this.lockedBody.update(result[0]);
48389 this.mainBody.update(result[1]);
48390 if(headersToo === true){
48391 this.updateHeaders();
48392 this.updateColumns();
48393 this.updateSplitters();
48394 this.updateHeaderSortState();
48396 this.syncRowHeights();
48398 this.fireEvent("refresh", this);
48401 handleColumnMove : function(cm, oldIndex, newIndex){
48402 this.indexMap = null;
48403 var s = this.getScrollState();
48404 this.refresh(true);
48405 this.restoreScroll(s);
48406 this.afterMove(newIndex);
48409 afterMove : function(colIndex){
48410 if(this.enableMoveAnim && Roo.enableFx){
48411 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48413 // if multisort - fix sortOrder, and reload..
48414 if (this.grid.dataSource.multiSort) {
48415 // the we can call sort again..
48416 var dm = this.grid.dataSource;
48417 var cm = this.grid.colModel;
48419 for(var i = 0; i < cm.config.length; i++ ) {
48421 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
48422 continue; // dont' bother, it's not in sort list or being set.
48425 so.push(cm.config[i].dataIndex);
48428 dm.load(dm.lastOptions);
48435 updateCell : function(dm, rowIndex, dataIndex){
48436 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48437 if(typeof colIndex == "undefined"){ // not present in grid
48440 var cm = this.grid.colModel;
48441 var cell = this.getCell(rowIndex, colIndex);
48442 var cellText = this.getCellText(rowIndex, colIndex);
48445 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48446 id : cm.getColumnId(colIndex),
48447 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48449 var renderer = cm.getRenderer(colIndex);
48450 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48451 if(typeof val == "undefined" || val === "") val = " ";
48452 cellText.innerHTML = val;
48453 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48454 this.syncRowHeights(rowIndex, rowIndex);
48457 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48459 if(this.grid.autoSizeHeaders){
48460 var h = this.getHeaderCellMeasure(colIndex);
48461 maxWidth = Math.max(maxWidth, h.scrollWidth);
48464 if(this.cm.isLocked(colIndex)){
48465 tb = this.getLockedTable();
48468 tb = this.getBodyTable();
48469 index = colIndex - this.cm.getLockedCount();
48472 var rows = tb.rows;
48473 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48474 for(var i = 0; i < stopIndex; i++){
48475 var cell = rows[i].childNodes[index].firstChild;
48476 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48479 return maxWidth + /*margin for error in IE*/ 5;
48482 * Autofit a column to its content.
48483 * @param {Number} colIndex
48484 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48486 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48487 if(this.cm.isHidden(colIndex)){
48488 return; // can't calc a hidden column
48491 var cid = this.cm.getColumnId(colIndex);
48492 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48493 if(this.grid.autoSizeHeaders){
48494 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48497 var newWidth = this.calcColumnWidth(colIndex);
48498 this.cm.setColumnWidth(colIndex,
48499 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48500 if(!suppressEvent){
48501 this.grid.fireEvent("columnresize", colIndex, newWidth);
48506 * Autofits all columns to their content and then expands to fit any extra space in the grid
48508 autoSizeColumns : function(){
48509 var cm = this.grid.colModel;
48510 var colCount = cm.getColumnCount();
48511 for(var i = 0; i < colCount; i++){
48512 this.autoSizeColumn(i, true, true);
48514 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48517 this.updateColumns();
48523 * Autofits all columns to the grid's width proportionate with their current size
48524 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48526 fitColumns : function(reserveScrollSpace){
48527 var cm = this.grid.colModel;
48528 var colCount = cm.getColumnCount();
48532 for (i = 0; i < colCount; i++){
48533 if(!cm.isHidden(i) && !cm.isFixed(i)){
48534 w = cm.getColumnWidth(i);
48540 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48541 if(reserveScrollSpace){
48544 var frac = (avail - cm.getTotalWidth())/width;
48545 while (cols.length){
48548 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48550 this.updateColumns();
48554 onRowSelect : function(rowIndex){
48555 var row = this.getRowComposite(rowIndex);
48556 row.addClass("x-grid-row-selected");
48559 onRowDeselect : function(rowIndex){
48560 var row = this.getRowComposite(rowIndex);
48561 row.removeClass("x-grid-row-selected");
48564 onCellSelect : function(row, col){
48565 var cell = this.getCell(row, col);
48567 Roo.fly(cell).addClass("x-grid-cell-selected");
48571 onCellDeselect : function(row, col){
48572 var cell = this.getCell(row, col);
48574 Roo.fly(cell).removeClass("x-grid-cell-selected");
48578 updateHeaderSortState : function(){
48580 // sort state can be single { field: xxx, direction : yyy}
48581 // or { xxx=>ASC , yyy : DESC ..... }
48584 if (!this.ds.multiSort) {
48585 var state = this.ds.getSortState();
48589 mstate[state.field] = state.direction;
48590 // FIXME... - this is not used here.. but might be elsewhere..
48591 this.sortState = state;
48594 mstate = this.ds.sortToggle;
48596 //remove existing sort classes..
48598 var sc = this.sortClasses;
48599 var hds = this.el.select(this.headerSelector).removeClass(sc);
48601 for(var f in mstate) {
48603 var sortColumn = this.cm.findColumnIndex(f);
48605 if(sortColumn != -1){
48606 var sortDir = mstate[f];
48607 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48616 handleHeaderClick : function(g, index){
48617 if(this.headersDisabled){
48620 var dm = g.dataSource, cm = g.colModel;
48621 if(!cm.isSortable(index)){
48626 if (dm.multiSort) {
48627 // update the sortOrder
48629 for(var i = 0; i < cm.config.length; i++ ) {
48631 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
48632 continue; // dont' bother, it's not in sort list or being set.
48635 so.push(cm.config[i].dataIndex);
48641 dm.sort(cm.getDataIndex(index));
48645 destroy : function(){
48647 this.colMenu.removeAll();
48648 Roo.menu.MenuMgr.unregister(this.colMenu);
48649 this.colMenu.getEl().remove();
48650 delete this.colMenu;
48653 this.hmenu.removeAll();
48654 Roo.menu.MenuMgr.unregister(this.hmenu);
48655 this.hmenu.getEl().remove();
48658 if(this.grid.enableColumnMove){
48659 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48661 for(var dd in dds){
48662 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48663 var elid = dds[dd].dragElId;
48665 Roo.get(elid).remove();
48666 } else if(dds[dd].config.isTarget){
48667 dds[dd].proxyTop.remove();
48668 dds[dd].proxyBottom.remove();
48671 if(Roo.dd.DDM.locationCache[dd]){
48672 delete Roo.dd.DDM.locationCache[dd];
48675 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48678 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48679 this.bind(null, null);
48680 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48683 handleLockChange : function(){
48684 this.refresh(true);
48687 onDenyColumnLock : function(){
48691 onDenyColumnHide : function(){
48695 handleHdMenuClick : function(item){
48696 var index = this.hdCtxIndex;
48697 var cm = this.cm, ds = this.ds;
48700 ds.sort(cm.getDataIndex(index), "ASC");
48703 ds.sort(cm.getDataIndex(index), "DESC");
48706 var lc = cm.getLockedCount();
48707 if(cm.getColumnCount(true) <= lc+1){
48708 this.onDenyColumnLock();
48712 cm.setLocked(index, true, true);
48713 cm.moveColumn(index, lc);
48714 this.grid.fireEvent("columnmove", index, lc);
48716 cm.setLocked(index, true);
48720 var lc = cm.getLockedCount();
48721 if((lc-1) != index){
48722 cm.setLocked(index, false, true);
48723 cm.moveColumn(index, lc-1);
48724 this.grid.fireEvent("columnmove", index, lc-1);
48726 cm.setLocked(index, false);
48730 index = cm.getIndexById(item.id.substr(4));
48732 if(item.checked && cm.getColumnCount(true) <= 1){
48733 this.onDenyColumnHide();
48736 cm.setHidden(index, item.checked);
48742 beforeColMenuShow : function(){
48743 var cm = this.cm, colCount = cm.getColumnCount();
48744 this.colMenu.removeAll();
48745 for(var i = 0; i < colCount; i++){
48746 this.colMenu.add(new Roo.menu.CheckItem({
48747 id: "col-"+cm.getColumnId(i),
48748 text: cm.getColumnHeader(i),
48749 checked: !cm.isHidden(i),
48755 handleHdCtx : function(g, index, e){
48757 var hd = this.getHeaderCell(index);
48758 this.hdCtxIndex = index;
48759 var ms = this.hmenu.items, cm = this.cm;
48760 ms.get("asc").setDisabled(!cm.isSortable(index));
48761 ms.get("desc").setDisabled(!cm.isSortable(index));
48762 if(this.grid.enableColLock !== false){
48763 ms.get("lock").setDisabled(cm.isLocked(index));
48764 ms.get("unlock").setDisabled(!cm.isLocked(index));
48766 this.hmenu.show(hd, "tl-bl");
48769 handleHdOver : function(e){
48770 var hd = this.findHeaderCell(e.getTarget());
48771 if(hd && !this.headersDisabled){
48772 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48773 this.fly(hd).addClass("x-grid-hd-over");
48778 handleHdOut : function(e){
48779 var hd = this.findHeaderCell(e.getTarget());
48781 this.fly(hd).removeClass("x-grid-hd-over");
48785 handleSplitDblClick : function(e, t){
48786 var i = this.getCellIndex(t);
48787 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48788 this.autoSizeColumn(i, true);
48793 render : function(){
48796 var colCount = cm.getColumnCount();
48798 if(this.grid.monitorWindowResize === true){
48799 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48801 var header = this.renderHeaders();
48802 var body = this.templates.body.apply({rows:""});
48803 var html = this.templates.master.apply({
48806 lockedHeader: header[0],
48810 //this.updateColumns();
48812 this.grid.getGridEl().dom.innerHTML = html;
48814 this.initElements();
48816 // a kludge to fix the random scolling effect in webkit
48817 this.el.on("scroll", function() {
48818 this.el.dom.scrollTop=0; // hopefully not recursive..
48821 this.scroller.on("scroll", this.handleScroll, this);
48822 this.lockedBody.on("mousewheel", this.handleWheel, this);
48823 this.mainBody.on("mousewheel", this.handleWheel, this);
48825 this.mainHd.on("mouseover", this.handleHdOver, this);
48826 this.mainHd.on("mouseout", this.handleHdOut, this);
48827 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48828 {delegate: "."+this.splitClass});
48830 this.lockedHd.on("mouseover", this.handleHdOver, this);
48831 this.lockedHd.on("mouseout", this.handleHdOut, this);
48832 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48833 {delegate: "."+this.splitClass});
48835 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48836 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48839 this.updateSplitters();
48841 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48842 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48843 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48846 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48847 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48849 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48850 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48852 if(this.grid.enableColLock !== false){
48853 this.hmenu.add('-',
48854 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48855 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48858 if(this.grid.enableColumnHide !== false){
48860 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48861 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48862 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48864 this.hmenu.add('-',
48865 {id:"columns", text: this.columnsText, menu: this.colMenu}
48868 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48870 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48873 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48874 this.dd = new Roo.grid.GridDragZone(this.grid, {
48875 ddGroup : this.grid.ddGroup || 'GridDD'
48880 for(var i = 0; i < colCount; i++){
48881 if(cm.isHidden(i)){
48882 this.hideColumn(i);
48884 if(cm.config[i].align){
48885 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48886 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48890 this.updateHeaderSortState();
48892 this.beforeInitialResize();
48895 // two part rendering gives faster view to the user
48896 this.renderPhase2.defer(1, this);
48899 renderPhase2 : function(){
48900 // render the rows now
48902 if(this.grid.autoSizeColumns){
48903 this.autoSizeColumns();
48907 beforeInitialResize : function(){
48911 onColumnSplitterMoved : function(i, w){
48912 this.userResized = true;
48913 var cm = this.grid.colModel;
48914 cm.setColumnWidth(i, w, true);
48915 var cid = cm.getColumnId(i);
48916 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48917 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48918 this.updateSplitters();
48920 this.grid.fireEvent("columnresize", i, w);
48923 syncRowHeights : function(startIndex, endIndex){
48924 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48925 startIndex = startIndex || 0;
48926 var mrows = this.getBodyTable().rows;
48927 var lrows = this.getLockedTable().rows;
48928 var len = mrows.length-1;
48929 endIndex = Math.min(endIndex || len, len);
48930 for(var i = startIndex; i <= endIndex; i++){
48931 var m = mrows[i], l = lrows[i];
48932 var h = Math.max(m.offsetHeight, l.offsetHeight);
48933 m.style.height = l.style.height = h + "px";
48938 layout : function(initialRender, is2ndPass){
48940 var auto = g.autoHeight;
48941 var scrollOffset = 16;
48942 var c = g.getGridEl(), cm = this.cm,
48943 expandCol = g.autoExpandColumn,
48945 //c.beginMeasure();
48947 if(!c.dom.offsetWidth){ // display:none?
48949 this.lockedWrap.show();
48950 this.mainWrap.show();
48955 var hasLock = this.cm.isLocked(0);
48957 var tbh = this.headerPanel.getHeight();
48958 var bbh = this.footerPanel.getHeight();
48961 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48962 var newHeight = ch + c.getBorderWidth("tb");
48964 newHeight = Math.min(g.maxHeight, newHeight);
48966 c.setHeight(newHeight);
48970 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48973 var s = this.scroller;
48975 var csize = c.getSize(true);
48977 this.el.setSize(csize.width, csize.height);
48979 this.headerPanel.setWidth(csize.width);
48980 this.footerPanel.setWidth(csize.width);
48982 var hdHeight = this.mainHd.getHeight();
48983 var vw = csize.width;
48984 var vh = csize.height - (tbh + bbh);
48988 var bt = this.getBodyTable();
48989 var ltWidth = hasLock ?
48990 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48992 var scrollHeight = bt.offsetHeight;
48993 var scrollWidth = ltWidth + bt.offsetWidth;
48994 var vscroll = false, hscroll = false;
48996 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48998 var lw = this.lockedWrap, mw = this.mainWrap;
48999 var lb = this.lockedBody, mb = this.mainBody;
49001 setTimeout(function(){
49002 var t = s.dom.offsetTop;
49003 var w = s.dom.clientWidth,
49004 h = s.dom.clientHeight;
49007 lw.setSize(ltWidth, h);
49009 mw.setLeftTop(ltWidth, t);
49010 mw.setSize(w-ltWidth, h);
49012 lb.setHeight(h-hdHeight);
49013 mb.setHeight(h-hdHeight);
49015 if(is2ndPass !== true && !gv.userResized && expandCol){
49016 // high speed resize without full column calculation
49018 var ci = cm.getIndexById(expandCol);
49020 ci = cm.findColumnIndex(expandCol);
49022 ci = Math.max(0, ci); // make sure it's got at least the first col.
49023 var expandId = cm.getColumnId(ci);
49024 var tw = cm.getTotalWidth(false);
49025 var currentWidth = cm.getColumnWidth(ci);
49026 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
49027 if(currentWidth != cw){
49028 cm.setColumnWidth(ci, cw, true);
49029 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49030 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49031 gv.updateSplitters();
49032 gv.layout(false, true);
49044 onWindowResize : function(){
49045 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
49051 appendFooter : function(parentEl){
49055 sortAscText : "Sort Ascending",
49056 sortDescText : "Sort Descending",
49057 lockText : "Lock Column",
49058 unlockText : "Unlock Column",
49059 columnsText : "Columns"
49063 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
49064 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
49065 this.proxy.el.addClass('x-grid3-col-dd');
49068 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
49069 handleMouseDown : function(e){
49073 callHandleMouseDown : function(e){
49074 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
49079 * Ext JS Library 1.1.1
49080 * Copyright(c) 2006-2007, Ext JS, LLC.
49082 * Originally Released Under LGPL - original licence link has changed is not relivant.
49085 * <script type="text/javascript">
49089 // This is a support class used internally by the Grid components
49090 Roo.grid.SplitDragZone = function(grid, hd, hd2){
49092 this.view = grid.getView();
49093 this.proxy = this.view.resizeProxy;
49094 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
49095 "gridSplitters" + this.grid.getGridEl().id, {
49096 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
49098 this.setHandleElId(Roo.id(hd));
49099 this.setOuterHandleElId(Roo.id(hd2));
49100 this.scroll = false;
49102 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
49103 fly: Roo.Element.fly,
49105 b4StartDrag : function(x, y){
49106 this.view.headersDisabled = true;
49107 this.proxy.setHeight(this.view.mainWrap.getHeight());
49108 var w = this.cm.getColumnWidth(this.cellIndex);
49109 var minw = Math.max(w-this.grid.minColumnWidth, 0);
49110 this.resetConstraints();
49111 this.setXConstraint(minw, 1000);
49112 this.setYConstraint(0, 0);
49113 this.minX = x - minw;
49114 this.maxX = x + 1000;
49116 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
49120 handleMouseDown : function(e){
49121 ev = Roo.EventObject.setEvent(e);
49122 var t = this.fly(ev.getTarget());
49123 if(t.hasClass("x-grid-split")){
49124 this.cellIndex = this.view.getCellIndex(t.dom);
49125 this.split = t.dom;
49126 this.cm = this.grid.colModel;
49127 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
49128 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
49133 endDrag : function(e){
49134 this.view.headersDisabled = false;
49135 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
49136 var diff = endX - this.startPos;
49137 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
49140 autoOffset : function(){
49141 this.setDelta(0,0);
49145 * Ext JS Library 1.1.1
49146 * Copyright(c) 2006-2007, Ext JS, LLC.
49148 * Originally Released Under LGPL - original licence link has changed is not relivant.
49151 * <script type="text/javascript">
49155 // This is a support class used internally by the Grid components
49156 Roo.grid.GridDragZone = function(grid, config){
49157 this.view = grid.getView();
49158 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
49159 if(this.view.lockedBody){
49160 this.setHandleElId(Roo.id(this.view.mainBody.dom));
49161 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
49163 this.scroll = false;
49165 this.ddel = document.createElement('div');
49166 this.ddel.className = 'x-grid-dd-wrap';
49169 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
49170 ddGroup : "GridDD",
49172 getDragData : function(e){
49173 var t = Roo.lib.Event.getTarget(e);
49174 var rowIndex = this.view.findRowIndex(t);
49175 if(rowIndex !== false){
49176 var sm = this.grid.selModel;
49177 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
49178 // sm.mouseDown(e, t);
49180 if (e.hasModifier()){
49181 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
49183 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
49188 onInitDrag : function(e){
49189 var data = this.dragData;
49190 this.ddel.innerHTML = this.grid.getDragDropText();
49191 this.proxy.update(this.ddel);
49192 // fire start drag?
49195 afterRepair : function(){
49196 this.dragging = false;
49199 getRepairXY : function(e, data){
49203 onEndDrag : function(data, e){
49207 onValidDrop : function(dd, e, id){
49212 beforeInvalidDrop : function(e, id){
49217 * Ext JS Library 1.1.1
49218 * Copyright(c) 2006-2007, Ext JS, LLC.
49220 * Originally Released Under LGPL - original licence link has changed is not relivant.
49223 * <script type="text/javascript">
49228 * @class Roo.grid.ColumnModel
49229 * @extends Roo.util.Observable
49230 * This is the default implementation of a ColumnModel used by the Grid. It defines
49231 * the columns in the grid.
49234 var colModel = new Roo.grid.ColumnModel([
49235 {header: "Ticker", width: 60, sortable: true, locked: true},
49236 {header: "Company Name", width: 150, sortable: true},
49237 {header: "Market Cap.", width: 100, sortable: true},
49238 {header: "$ Sales", width: 100, sortable: true, renderer: money},
49239 {header: "Employees", width: 100, sortable: true, resizable: false}
49244 * The config options listed for this class are options which may appear in each
49245 * individual column definition.
49246 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
49248 * @param {Object} config An Array of column config objects. See this class's
49249 * config objects for details.
49251 Roo.grid.ColumnModel = function(config){
49253 * The config passed into the constructor
49255 this.config = config;
49258 // if no id, create one
49259 // if the column does not have a dataIndex mapping,
49260 // map it to the order it is in the config
49261 for(var i = 0, len = config.length; i < len; i++){
49263 if(typeof c.dataIndex == "undefined"){
49266 if(typeof c.renderer == "string"){
49267 c.renderer = Roo.util.Format[c.renderer];
49269 if(typeof c.id == "undefined"){
49272 if(c.editor && c.editor.xtype){
49273 c.editor = Roo.factory(c.editor, Roo.grid);
49275 if(c.editor && c.editor.isFormField){
49276 c.editor = new Roo.grid.GridEditor(c.editor);
49278 this.lookup[c.id] = c;
49282 * The width of columns which have no width specified (defaults to 100)
49285 this.defaultWidth = 100;
49288 * Default sortable of columns which have no sortable specified (defaults to false)
49291 this.defaultSortable = false;
49295 * @event widthchange
49296 * Fires when the width of a column changes.
49297 * @param {ColumnModel} this
49298 * @param {Number} columnIndex The column index
49299 * @param {Number} newWidth The new width
49301 "widthchange": true,
49303 * @event headerchange
49304 * Fires when the text of a header changes.
49305 * @param {ColumnModel} this
49306 * @param {Number} columnIndex The column index
49307 * @param {Number} newText The new header text
49309 "headerchange": true,
49311 * @event hiddenchange
49312 * Fires when a column is hidden or "unhidden".
49313 * @param {ColumnModel} this
49314 * @param {Number} columnIndex The column index
49315 * @param {Boolean} hidden true if hidden, false otherwise
49317 "hiddenchange": true,
49319 * @event columnmoved
49320 * Fires when a column is moved.
49321 * @param {ColumnModel} this
49322 * @param {Number} oldIndex
49323 * @param {Number} newIndex
49325 "columnmoved" : true,
49327 * @event columlockchange
49328 * Fires when a column's locked state is changed
49329 * @param {ColumnModel} this
49330 * @param {Number} colIndex
49331 * @param {Boolean} locked true if locked
49333 "columnlockchange" : true
49335 Roo.grid.ColumnModel.superclass.constructor.call(this);
49337 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
49339 * @cfg {String} header The header text to display in the Grid view.
49342 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
49343 * {@link Roo.data.Record} definition from which to draw the column's value. If not
49344 * specified, the column's index is used as an index into the Record's data Array.
49347 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
49348 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
49351 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
49352 * Defaults to the value of the {@link #defaultSortable} property.
49353 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
49356 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
49359 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
49362 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
49365 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
49368 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
49369 * given the cell's data value. See {@link #setRenderer}. If not specified, the
49370 * default renderer uses the raw data value.
49373 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
49376 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
49380 * Returns the id of the column at the specified index.
49381 * @param {Number} index The column index
49382 * @return {String} the id
49384 getColumnId : function(index){
49385 return this.config[index].id;
49389 * Returns the column for a specified id.
49390 * @param {String} id The column id
49391 * @return {Object} the column
49393 getColumnById : function(id){
49394 return this.lookup[id];
49399 * Returns the column for a specified dataIndex.
49400 * @param {String} dataIndex The column dataIndex
49401 * @return {Object|Boolean} the column or false if not found
49403 getColumnByDataIndex: function(dataIndex){
49404 var index = this.findColumnIndex(dataIndex);
49405 return index > -1 ? this.config[index] : false;
49409 * Returns the index for a specified column id.
49410 * @param {String} id The column id
49411 * @return {Number} the index, or -1 if not found
49413 getIndexById : function(id){
49414 for(var i = 0, len = this.config.length; i < len; i++){
49415 if(this.config[i].id == id){
49423 * Returns the index for a specified column dataIndex.
49424 * @param {String} dataIndex The column dataIndex
49425 * @return {Number} the index, or -1 if not found
49428 findColumnIndex : function(dataIndex){
49429 for(var i = 0, len = this.config.length; i < len; i++){
49430 if(this.config[i].dataIndex == dataIndex){
49438 moveColumn : function(oldIndex, newIndex){
49439 var c = this.config[oldIndex];
49440 this.config.splice(oldIndex, 1);
49441 this.config.splice(newIndex, 0, c);
49442 this.dataMap = null;
49443 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49446 isLocked : function(colIndex){
49447 return this.config[colIndex].locked === true;
49450 setLocked : function(colIndex, value, suppressEvent){
49451 if(this.isLocked(colIndex) == value){
49454 this.config[colIndex].locked = value;
49455 if(!suppressEvent){
49456 this.fireEvent("columnlockchange", this, colIndex, value);
49460 getTotalLockedWidth : function(){
49461 var totalWidth = 0;
49462 for(var i = 0; i < this.config.length; i++){
49463 if(this.isLocked(i) && !this.isHidden(i)){
49464 this.totalWidth += this.getColumnWidth(i);
49470 getLockedCount : function(){
49471 for(var i = 0, len = this.config.length; i < len; i++){
49472 if(!this.isLocked(i)){
49479 * Returns the number of columns.
49482 getColumnCount : function(visibleOnly){
49483 if(visibleOnly === true){
49485 for(var i = 0, len = this.config.length; i < len; i++){
49486 if(!this.isHidden(i)){
49492 return this.config.length;
49496 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49497 * @param {Function} fn
49498 * @param {Object} scope (optional)
49499 * @return {Array} result
49501 getColumnsBy : function(fn, scope){
49503 for(var i = 0, len = this.config.length; i < len; i++){
49504 var c = this.config[i];
49505 if(fn.call(scope||this, c, i) === true){
49513 * Returns true if the specified column is sortable.
49514 * @param {Number} col The column index
49515 * @return {Boolean}
49517 isSortable : function(col){
49518 if(typeof this.config[col].sortable == "undefined"){
49519 return this.defaultSortable;
49521 return this.config[col].sortable;
49525 * Returns the rendering (formatting) function defined for the column.
49526 * @param {Number} col The column index.
49527 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49529 getRenderer : function(col){
49530 if(!this.config[col].renderer){
49531 return Roo.grid.ColumnModel.defaultRenderer;
49533 return this.config[col].renderer;
49537 * Sets the rendering (formatting) function for a column.
49538 * @param {Number} col The column index
49539 * @param {Function} fn The function to use to process the cell's raw data
49540 * to return HTML markup for the grid view. The render function is called with
49541 * the following parameters:<ul>
49542 * <li>Data value.</li>
49543 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49544 * <li>css A CSS style string to apply to the table cell.</li>
49545 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49546 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49547 * <li>Row index</li>
49548 * <li>Column index</li>
49549 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49551 setRenderer : function(col, fn){
49552 this.config[col].renderer = fn;
49556 * Returns the width for the specified column.
49557 * @param {Number} col The column index
49560 getColumnWidth : function(col){
49561 return this.config[col].width * 1 || this.defaultWidth;
49565 * Sets the width for a column.
49566 * @param {Number} col The column index
49567 * @param {Number} width The new width
49569 setColumnWidth : function(col, width, suppressEvent){
49570 this.config[col].width = width;
49571 this.totalWidth = null;
49572 if(!suppressEvent){
49573 this.fireEvent("widthchange", this, col, width);
49578 * Returns the total width of all columns.
49579 * @param {Boolean} includeHidden True to include hidden column widths
49582 getTotalWidth : function(includeHidden){
49583 if(!this.totalWidth){
49584 this.totalWidth = 0;
49585 for(var i = 0, len = this.config.length; i < len; i++){
49586 if(includeHidden || !this.isHidden(i)){
49587 this.totalWidth += this.getColumnWidth(i);
49591 return this.totalWidth;
49595 * Returns the header for the specified column.
49596 * @param {Number} col The column index
49599 getColumnHeader : function(col){
49600 return this.config[col].header;
49604 * Sets the header for a column.
49605 * @param {Number} col The column index
49606 * @param {String} header The new header
49608 setColumnHeader : function(col, header){
49609 this.config[col].header = header;
49610 this.fireEvent("headerchange", this, col, header);
49614 * Returns the tooltip for the specified column.
49615 * @param {Number} col The column index
49618 getColumnTooltip : function(col){
49619 return this.config[col].tooltip;
49622 * Sets the tooltip for a column.
49623 * @param {Number} col The column index
49624 * @param {String} tooltip The new tooltip
49626 setColumnTooltip : function(col, tooltip){
49627 this.config[col].tooltip = tooltip;
49631 * Returns the dataIndex for the specified column.
49632 * @param {Number} col The column index
49635 getDataIndex : function(col){
49636 return this.config[col].dataIndex;
49640 * Sets the dataIndex for a column.
49641 * @param {Number} col The column index
49642 * @param {Number} dataIndex The new dataIndex
49644 setDataIndex : function(col, dataIndex){
49645 this.config[col].dataIndex = dataIndex;
49651 * Returns true if the cell is editable.
49652 * @param {Number} colIndex The column index
49653 * @param {Number} rowIndex The row index
49654 * @return {Boolean}
49656 isCellEditable : function(colIndex, rowIndex){
49657 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49661 * Returns the editor defined for the cell/column.
49662 * return false or null to disable editing.
49663 * @param {Number} colIndex The column index
49664 * @param {Number} rowIndex The row index
49667 getCellEditor : function(colIndex, rowIndex){
49668 return this.config[colIndex].editor;
49672 * Sets if a column is editable.
49673 * @param {Number} col The column index
49674 * @param {Boolean} editable True if the column is editable
49676 setEditable : function(col, editable){
49677 this.config[col].editable = editable;
49682 * Returns true if the column is hidden.
49683 * @param {Number} colIndex The column index
49684 * @return {Boolean}
49686 isHidden : function(colIndex){
49687 return this.config[colIndex].hidden;
49692 * Returns true if the column width cannot be changed
49694 isFixed : function(colIndex){
49695 return this.config[colIndex].fixed;
49699 * Returns true if the column can be resized
49700 * @return {Boolean}
49702 isResizable : function(colIndex){
49703 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49706 * Sets if a column is hidden.
49707 * @param {Number} colIndex The column index
49708 * @param {Boolean} hidden True if the column is hidden
49710 setHidden : function(colIndex, hidden){
49711 this.config[colIndex].hidden = hidden;
49712 this.totalWidth = null;
49713 this.fireEvent("hiddenchange", this, colIndex, hidden);
49717 * Sets the editor for a column.
49718 * @param {Number} col The column index
49719 * @param {Object} editor The editor object
49721 setEditor : function(col, editor){
49722 this.config[col].editor = editor;
49726 Roo.grid.ColumnModel.defaultRenderer = function(value){
49727 if(typeof value == "string" && value.length < 1){
49733 // Alias for backwards compatibility
49734 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49737 * Ext JS Library 1.1.1
49738 * Copyright(c) 2006-2007, Ext JS, LLC.
49740 * Originally Released Under LGPL - original licence link has changed is not relivant.
49743 * <script type="text/javascript">
49747 * @class Roo.grid.AbstractSelectionModel
49748 * @extends Roo.util.Observable
49749 * Abstract base class for grid SelectionModels. It provides the interface that should be
49750 * implemented by descendant classes. This class should not be directly instantiated.
49753 Roo.grid.AbstractSelectionModel = function(){
49754 this.locked = false;
49755 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49758 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49759 /** @ignore Called by the grid automatically. Do not call directly. */
49760 init : function(grid){
49766 * Locks the selections.
49769 this.locked = true;
49773 * Unlocks the selections.
49775 unlock : function(){
49776 this.locked = false;
49780 * Returns true if the selections are locked.
49781 * @return {Boolean}
49783 isLocked : function(){
49784 return this.locked;
49788 * Ext JS Library 1.1.1
49789 * Copyright(c) 2006-2007, Ext JS, LLC.
49791 * Originally Released Under LGPL - original licence link has changed is not relivant.
49794 * <script type="text/javascript">
49797 * @extends Roo.grid.AbstractSelectionModel
49798 * @class Roo.grid.RowSelectionModel
49799 * The default SelectionModel used by {@link Roo.grid.Grid}.
49800 * It supports multiple selections and keyboard selection/navigation.
49802 * @param {Object} config
49804 Roo.grid.RowSelectionModel = function(config){
49805 Roo.apply(this, config);
49806 this.selections = new Roo.util.MixedCollection(false, function(o){
49811 this.lastActive = false;
49815 * @event selectionchange
49816 * Fires when the selection changes
49817 * @param {SelectionModel} this
49819 "selectionchange" : true,
49821 * @event afterselectionchange
49822 * Fires after the selection changes (eg. by key press or clicking)
49823 * @param {SelectionModel} this
49825 "afterselectionchange" : true,
49827 * @event beforerowselect
49828 * Fires when a row is selected being selected, return false to cancel.
49829 * @param {SelectionModel} this
49830 * @param {Number} rowIndex The selected index
49831 * @param {Boolean} keepExisting False if other selections will be cleared
49833 "beforerowselect" : true,
49836 * Fires when a row is selected.
49837 * @param {SelectionModel} this
49838 * @param {Number} rowIndex The selected index
49839 * @param {Roo.data.Record} r The record
49841 "rowselect" : true,
49843 * @event rowdeselect
49844 * Fires when a row is deselected.
49845 * @param {SelectionModel} this
49846 * @param {Number} rowIndex The selected index
49848 "rowdeselect" : true
49850 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49851 this.locked = false;
49854 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49856 * @cfg {Boolean} singleSelect
49857 * True to allow selection of only one row at a time (defaults to false)
49859 singleSelect : false,
49862 initEvents : function(){
49864 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49865 this.grid.on("mousedown", this.handleMouseDown, this);
49866 }else{ // allow click to work like normal
49867 this.grid.on("rowclick", this.handleDragableRowClick, this);
49870 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49871 "up" : function(e){
49873 this.selectPrevious(e.shiftKey);
49874 }else if(this.last !== false && this.lastActive !== false){
49875 var last = this.last;
49876 this.selectRange(this.last, this.lastActive-1);
49877 this.grid.getView().focusRow(this.lastActive);
49878 if(last !== false){
49882 this.selectFirstRow();
49884 this.fireEvent("afterselectionchange", this);
49886 "down" : function(e){
49888 this.selectNext(e.shiftKey);
49889 }else if(this.last !== false && this.lastActive !== false){
49890 var last = this.last;
49891 this.selectRange(this.last, this.lastActive+1);
49892 this.grid.getView().focusRow(this.lastActive);
49893 if(last !== false){
49897 this.selectFirstRow();
49899 this.fireEvent("afterselectionchange", this);
49904 var view = this.grid.view;
49905 view.on("refresh", this.onRefresh, this);
49906 view.on("rowupdated", this.onRowUpdated, this);
49907 view.on("rowremoved", this.onRemove, this);
49911 onRefresh : function(){
49912 var ds = this.grid.dataSource, i, v = this.grid.view;
49913 var s = this.selections;
49914 s.each(function(r){
49915 if((i = ds.indexOfId(r.id)) != -1){
49924 onRemove : function(v, index, r){
49925 this.selections.remove(r);
49929 onRowUpdated : function(v, index, r){
49930 if(this.isSelected(r)){
49931 v.onRowSelect(index);
49937 * @param {Array} records The records to select
49938 * @param {Boolean} keepExisting (optional) True to keep existing selections
49940 selectRecords : function(records, keepExisting){
49942 this.clearSelections();
49944 var ds = this.grid.dataSource;
49945 for(var i = 0, len = records.length; i < len; i++){
49946 this.selectRow(ds.indexOf(records[i]), true);
49951 * Gets the number of selected rows.
49954 getCount : function(){
49955 return this.selections.length;
49959 * Selects the first row in the grid.
49961 selectFirstRow : function(){
49966 * Select the last row.
49967 * @param {Boolean} keepExisting (optional) True to keep existing selections
49969 selectLastRow : function(keepExisting){
49970 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49974 * Selects the row immediately following the last selected row.
49975 * @param {Boolean} keepExisting (optional) True to keep existing selections
49977 selectNext : function(keepExisting){
49978 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49979 this.selectRow(this.last+1, keepExisting);
49980 this.grid.getView().focusRow(this.last);
49985 * Selects the row that precedes the last selected row.
49986 * @param {Boolean} keepExisting (optional) True to keep existing selections
49988 selectPrevious : function(keepExisting){
49990 this.selectRow(this.last-1, keepExisting);
49991 this.grid.getView().focusRow(this.last);
49996 * Returns the selected records
49997 * @return {Array} Array of selected records
49999 getSelections : function(){
50000 return [].concat(this.selections.items);
50004 * Returns the first selected record.
50007 getSelected : function(){
50008 return this.selections.itemAt(0);
50013 * Clears all selections.
50015 clearSelections : function(fast){
50016 if(this.locked) return;
50018 var ds = this.grid.dataSource;
50019 var s = this.selections;
50020 s.each(function(r){
50021 this.deselectRow(ds.indexOfId(r.id));
50025 this.selections.clear();
50032 * Selects all rows.
50034 selectAll : function(){
50035 if(this.locked) return;
50036 this.selections.clear();
50037 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
50038 this.selectRow(i, true);
50043 * Returns True if there is a selection.
50044 * @return {Boolean}
50046 hasSelection : function(){
50047 return this.selections.length > 0;
50051 * Returns True if the specified row is selected.
50052 * @param {Number/Record} record The record or index of the record to check
50053 * @return {Boolean}
50055 isSelected : function(index){
50056 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
50057 return (r && this.selections.key(r.id) ? true : false);
50061 * Returns True if the specified record id is selected.
50062 * @param {String} id The id of record to check
50063 * @return {Boolean}
50065 isIdSelected : function(id){
50066 return (this.selections.key(id) ? true : false);
50070 handleMouseDown : function(e, t){
50071 var view = this.grid.getView(), rowIndex;
50072 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
50075 if(e.shiftKey && this.last !== false){
50076 var last = this.last;
50077 this.selectRange(last, rowIndex, e.ctrlKey);
50078 this.last = last; // reset the last
50079 view.focusRow(rowIndex);
50081 var isSelected = this.isSelected(rowIndex);
50082 if(e.button !== 0 && isSelected){
50083 view.focusRow(rowIndex);
50084 }else if(e.ctrlKey && isSelected){
50085 this.deselectRow(rowIndex);
50086 }else if(!isSelected){
50087 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
50088 view.focusRow(rowIndex);
50091 this.fireEvent("afterselectionchange", this);
50094 handleDragableRowClick : function(grid, rowIndex, e)
50096 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
50097 this.selectRow(rowIndex, false);
50098 grid.view.focusRow(rowIndex);
50099 this.fireEvent("afterselectionchange", this);
50104 * Selects multiple rows.
50105 * @param {Array} rows Array of the indexes of the row to select
50106 * @param {Boolean} keepExisting (optional) True to keep existing selections
50108 selectRows : function(rows, keepExisting){
50110 this.clearSelections();
50112 for(var i = 0, len = rows.length; i < len; i++){
50113 this.selectRow(rows[i], true);
50118 * Selects a range of rows. All rows in between startRow and endRow are also selected.
50119 * @param {Number} startRow The index of the first row in the range
50120 * @param {Number} endRow The index of the last row in the range
50121 * @param {Boolean} keepExisting (optional) True to retain existing selections
50123 selectRange : function(startRow, endRow, keepExisting){
50124 if(this.locked) return;
50126 this.clearSelections();
50128 if(startRow <= endRow){
50129 for(var i = startRow; i <= endRow; i++){
50130 this.selectRow(i, true);
50133 for(var i = startRow; i >= endRow; i--){
50134 this.selectRow(i, true);
50140 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
50141 * @param {Number} startRow The index of the first row in the range
50142 * @param {Number} endRow The index of the last row in the range
50144 deselectRange : function(startRow, endRow, preventViewNotify){
50145 if(this.locked) return;
50146 for(var i = startRow; i <= endRow; i++){
50147 this.deselectRow(i, preventViewNotify);
50153 * @param {Number} row The index of the row to select
50154 * @param {Boolean} keepExisting (optional) True to keep existing selections
50156 selectRow : function(index, keepExisting, preventViewNotify){
50157 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
50158 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
50159 if(!keepExisting || this.singleSelect){
50160 this.clearSelections();
50162 var r = this.grid.dataSource.getAt(index);
50163 this.selections.add(r);
50164 this.last = this.lastActive = index;
50165 if(!preventViewNotify){
50166 this.grid.getView().onRowSelect(index);
50168 this.fireEvent("rowselect", this, index, r);
50169 this.fireEvent("selectionchange", this);
50175 * @param {Number} row The index of the row to deselect
50177 deselectRow : function(index, preventViewNotify){
50178 if(this.locked) return;
50179 if(this.last == index){
50182 if(this.lastActive == index){
50183 this.lastActive = false;
50185 var r = this.grid.dataSource.getAt(index);
50186 this.selections.remove(r);
50187 if(!preventViewNotify){
50188 this.grid.getView().onRowDeselect(index);
50190 this.fireEvent("rowdeselect", this, index);
50191 this.fireEvent("selectionchange", this);
50195 restoreLast : function(){
50197 this.last = this._last;
50202 acceptsNav : function(row, col, cm){
50203 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50207 onEditorKey : function(field, e){
50208 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50213 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50215 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50217 }else if(k == e.ENTER && !e.ctrlKey){
50221 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
50223 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
50225 }else if(k == e.ESC){
50229 g.startEditing(newCell[0], newCell[1]);
50234 * Ext JS Library 1.1.1
50235 * Copyright(c) 2006-2007, Ext JS, LLC.
50237 * Originally Released Under LGPL - original licence link has changed is not relivant.
50240 * <script type="text/javascript">
50243 * @class Roo.grid.CellSelectionModel
50244 * @extends Roo.grid.AbstractSelectionModel
50245 * This class provides the basic implementation for cell selection in a grid.
50247 * @param {Object} config The object containing the configuration of this model.
50249 Roo.grid.CellSelectionModel = function(config){
50250 Roo.apply(this, config);
50252 this.selection = null;
50256 * @event beforerowselect
50257 * Fires before a cell is selected.
50258 * @param {SelectionModel} this
50259 * @param {Number} rowIndex The selected row index
50260 * @param {Number} colIndex The selected cell index
50262 "beforecellselect" : true,
50264 * @event cellselect
50265 * Fires when a cell is selected.
50266 * @param {SelectionModel} this
50267 * @param {Number} rowIndex The selected row index
50268 * @param {Number} colIndex The selected cell index
50270 "cellselect" : true,
50272 * @event selectionchange
50273 * Fires when the active selection changes.
50274 * @param {SelectionModel} this
50275 * @param {Object} selection null for no selection or an object (o) with two properties
50277 <li>o.record: the record object for the row the selection is in</li>
50278 <li>o.cell: An array of [rowIndex, columnIndex]</li>
50281 "selectionchange" : true
50283 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
50286 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
50289 initEvents : function(){
50290 this.grid.on("mousedown", this.handleMouseDown, this);
50291 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
50292 var view = this.grid.view;
50293 view.on("refresh", this.onViewChange, this);
50294 view.on("rowupdated", this.onRowUpdated, this);
50295 view.on("beforerowremoved", this.clearSelections, this);
50296 view.on("beforerowsinserted", this.clearSelections, this);
50297 if(this.grid.isEditor){
50298 this.grid.on("beforeedit", this.beforeEdit, this);
50303 beforeEdit : function(e){
50304 this.select(e.row, e.column, false, true, e.record);
50308 onRowUpdated : function(v, index, r){
50309 if(this.selection && this.selection.record == r){
50310 v.onCellSelect(index, this.selection.cell[1]);
50315 onViewChange : function(){
50316 this.clearSelections(true);
50320 * Returns the currently selected cell,.
50321 * @return {Array} The selected cell (row, column) or null if none selected.
50323 getSelectedCell : function(){
50324 return this.selection ? this.selection.cell : null;
50328 * Clears all selections.
50329 * @param {Boolean} true to prevent the gridview from being notified about the change.
50331 clearSelections : function(preventNotify){
50332 var s = this.selection;
50334 if(preventNotify !== true){
50335 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
50337 this.selection = null;
50338 this.fireEvent("selectionchange", this, null);
50343 * Returns true if there is a selection.
50344 * @return {Boolean}
50346 hasSelection : function(){
50347 return this.selection ? true : false;
50351 handleMouseDown : function(e, t){
50352 var v = this.grid.getView();
50353 if(this.isLocked()){
50356 var row = v.findRowIndex(t);
50357 var cell = v.findCellIndex(t);
50358 if(row !== false && cell !== false){
50359 this.select(row, cell);
50365 * @param {Number} rowIndex
50366 * @param {Number} collIndex
50368 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
50369 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
50370 this.clearSelections();
50371 r = r || this.grid.dataSource.getAt(rowIndex);
50374 cell : [rowIndex, colIndex]
50376 if(!preventViewNotify){
50377 var v = this.grid.getView();
50378 v.onCellSelect(rowIndex, colIndex);
50379 if(preventFocus !== true){
50380 v.focusCell(rowIndex, colIndex);
50383 this.fireEvent("cellselect", this, rowIndex, colIndex);
50384 this.fireEvent("selectionchange", this, this.selection);
50389 isSelectable : function(rowIndex, colIndex, cm){
50390 return !cm.isHidden(colIndex);
50394 handleKeyDown : function(e){
50395 Roo.log('Cell Sel Model handleKeyDown');
50396 if(!e.isNavKeyPress()){
50399 var g = this.grid, s = this.selection;
50402 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50404 this.select(cell[0], cell[1]);
50409 var walk = function(row, col, step){
50410 return g.walkCells(row, col, step, sm.isSelectable, sm);
50412 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50417 // handled by onEditorKey
50418 if (g.isEditor && g.editing) {
50422 newCell = walk(r, c-1, -1);
50424 newCell = walk(r, c+1, 1);
50428 newCell = walk(r+1, c, 1);
50431 newCell = walk(r-1, c, -1);
50434 newCell = walk(r, c+1, 1);
50437 newCell = walk(r, c-1, -1);
50440 if(g.isEditor && !g.editing){
50441 g.startEditing(r, c);
50448 this.select(newCell[0], newCell[1]);
50453 acceptsNav : function(row, col, cm){
50454 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50457 onEditorKey : function(field, e){
50459 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50460 ///Roo.log('onEditorKey' + k);
50464 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50466 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50469 }else if(k == e.ENTER && !e.ctrlKey){
50472 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50473 }else if(k == e.ESC){
50479 //Roo.log('next cell after edit');
50480 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50485 * Ext JS Library 1.1.1
50486 * Copyright(c) 2006-2007, Ext JS, LLC.
50488 * Originally Released Under LGPL - original licence link has changed is not relivant.
50491 * <script type="text/javascript">
50495 * @class Roo.grid.EditorGrid
50496 * @extends Roo.grid.Grid
50497 * Class for creating and editable grid.
50498 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50499 * The container MUST have some type of size defined for the grid to fill. The container will be
50500 * automatically set to position relative if it isn't already.
50501 * @param {Object} dataSource The data model to bind to
50502 * @param {Object} colModel The column model with info about this grid's columns
50504 Roo.grid.EditorGrid = function(container, config){
50505 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50506 this.getGridEl().addClass("xedit-grid");
50508 if(!this.selModel){
50509 this.selModel = new Roo.grid.CellSelectionModel();
50512 this.activeEditor = null;
50516 * @event beforeedit
50517 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50518 * <ul style="padding:5px;padding-left:16px;">
50519 * <li>grid - This grid</li>
50520 * <li>record - The record being edited</li>
50521 * <li>field - The field name being edited</li>
50522 * <li>value - The value for the field being edited.</li>
50523 * <li>row - The grid row index</li>
50524 * <li>column - The grid column index</li>
50525 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50527 * @param {Object} e An edit event (see above for description)
50529 "beforeedit" : true,
50532 * Fires after a cell is edited. <br />
50533 * <ul style="padding:5px;padding-left:16px;">
50534 * <li>grid - This grid</li>
50535 * <li>record - The record being edited</li>
50536 * <li>field - The field name being edited</li>
50537 * <li>value - The value being set</li>
50538 * <li>originalValue - The original value for the field, before the edit.</li>
50539 * <li>row - The grid row index</li>
50540 * <li>column - The grid column index</li>
50542 * @param {Object} e An edit event (see above for description)
50544 "afteredit" : true,
50546 * @event validateedit
50547 * Fires after a cell is edited, but before the value is set in the record.
50548 * You can use this to modify the value being set in the field, Return false
50549 * to cancel the change. The edit event object has the following properties <br />
50550 * <ul style="padding:5px;padding-left:16px;">
50551 * <li>editor - This editor</li>
50552 * <li>grid - This grid</li>
50553 * <li>record - The record being edited</li>
50554 * <li>field - The field name being edited</li>
50555 * <li>value - The value being set</li>
50556 * <li>originalValue - The original value for the field, before the edit.</li>
50557 * <li>row - The grid row index</li>
50558 * <li>column - The grid column index</li>
50559 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50561 * @param {Object} e An edit event (see above for description)
50563 "validateedit" : true
50565 this.on("bodyscroll", this.stopEditing, this);
50566 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50569 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50571 * @cfg {Number} clicksToEdit
50572 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50579 trackMouseOver: false, // causes very odd FF errors
50581 onCellDblClick : function(g, row, col){
50582 this.startEditing(row, col);
50585 onEditComplete : function(ed, value, startValue){
50586 this.editing = false;
50587 this.activeEditor = null;
50588 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50590 var field = this.colModel.getDataIndex(ed.col);
50595 originalValue: startValue,
50602 if(String(value) !== String(startValue)){
50604 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50605 r.set(field, e.value);
50606 // if we are dealing with a combo box..
50607 // then we also set the 'name' colum to be the displayField
50608 if (ed.field.displayField && ed.field.name) {
50609 r.set(ed.field.name, ed.field.el.dom.value);
50612 delete e.cancel; //?? why!!!
50613 this.fireEvent("afteredit", e);
50616 this.fireEvent("afteredit", e); // always fire it!
50618 this.view.focusCell(ed.row, ed.col);
50622 * Starts editing the specified for the specified row/column
50623 * @param {Number} rowIndex
50624 * @param {Number} colIndex
50626 startEditing : function(row, col){
50627 this.stopEditing();
50628 if(this.colModel.isCellEditable(col, row)){
50629 this.view.ensureVisible(row, col, true);
50630 var r = this.dataSource.getAt(row);
50631 var field = this.colModel.getDataIndex(col);
50636 value: r.data[field],
50641 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50642 this.editing = true;
50643 var ed = this.colModel.getCellEditor(col, row);
50649 ed.render(ed.parentEl || document.body);
50652 (function(){ // complex but required for focus issues in safari, ie and opera
50656 ed.on("complete", this.onEditComplete, this, {single: true});
50657 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50658 this.activeEditor = ed;
50659 var v = r.data[field];
50660 ed.startEdit(this.view.getCell(row, col), v);
50661 // combo's with 'displayField and name set
50662 if (ed.field.displayField && ed.field.name) {
50663 ed.field.el.dom.value = r.data[ed.field.name];
50667 }).defer(50, this);
50673 * Stops any active editing
50675 stopEditing : function(){
50676 if(this.activeEditor){
50677 this.activeEditor.completeEdit();
50679 this.activeEditor = null;
50683 * Ext JS Library 1.1.1
50684 * Copyright(c) 2006-2007, Ext JS, LLC.
50686 * Originally Released Under LGPL - original licence link has changed is not relivant.
50689 * <script type="text/javascript">
50692 // private - not really -- you end up using it !
50693 // This is a support class used internally by the Grid components
50696 * @class Roo.grid.GridEditor
50697 * @extends Roo.Editor
50698 * Class for creating and editable grid elements.
50699 * @param {Object} config any settings (must include field)
50701 Roo.grid.GridEditor = function(field, config){
50702 if (!config && field.field) {
50704 field = Roo.factory(config.field, Roo.form);
50706 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50707 field.monitorTab = false;
50710 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50713 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50716 alignment: "tl-tl",
50719 cls: "x-small-editor x-grid-editor",
50724 * Ext JS Library 1.1.1
50725 * Copyright(c) 2006-2007, Ext JS, LLC.
50727 * Originally Released Under LGPL - original licence link has changed is not relivant.
50730 * <script type="text/javascript">
50735 Roo.grid.PropertyRecord = Roo.data.Record.create([
50736 {name:'name',type:'string'}, 'value'
50740 Roo.grid.PropertyStore = function(grid, source){
50742 this.store = new Roo.data.Store({
50743 recordType : Roo.grid.PropertyRecord
50745 this.store.on('update', this.onUpdate, this);
50747 this.setSource(source);
50749 Roo.grid.PropertyStore.superclass.constructor.call(this);
50754 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50755 setSource : function(o){
50757 this.store.removeAll();
50760 if(this.isEditableValue(o[k])){
50761 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50764 this.store.loadRecords({records: data}, {}, true);
50767 onUpdate : function(ds, record, type){
50768 if(type == Roo.data.Record.EDIT){
50769 var v = record.data['value'];
50770 var oldValue = record.modified['value'];
50771 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50772 this.source[record.id] = v;
50774 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50781 getProperty : function(row){
50782 return this.store.getAt(row);
50785 isEditableValue: function(val){
50786 if(val && val instanceof Date){
50788 }else if(typeof val == 'object' || typeof val == 'function'){
50794 setValue : function(prop, value){
50795 this.source[prop] = value;
50796 this.store.getById(prop).set('value', value);
50799 getSource : function(){
50800 return this.source;
50804 Roo.grid.PropertyColumnModel = function(grid, store){
50807 g.PropertyColumnModel.superclass.constructor.call(this, [
50808 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50809 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50811 this.store = store;
50812 this.bselect = Roo.DomHelper.append(document.body, {
50813 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50814 {tag: 'option', value: 'true', html: 'true'},
50815 {tag: 'option', value: 'false', html: 'false'}
50818 Roo.id(this.bselect);
50821 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50822 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50823 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50824 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50825 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50827 this.renderCellDelegate = this.renderCell.createDelegate(this);
50828 this.renderPropDelegate = this.renderProp.createDelegate(this);
50831 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50835 valueText : 'Value',
50837 dateFormat : 'm/j/Y',
50840 renderDate : function(dateVal){
50841 return dateVal.dateFormat(this.dateFormat);
50844 renderBool : function(bVal){
50845 return bVal ? 'true' : 'false';
50848 isCellEditable : function(colIndex, rowIndex){
50849 return colIndex == 1;
50852 getRenderer : function(col){
50854 this.renderCellDelegate : this.renderPropDelegate;
50857 renderProp : function(v){
50858 return this.getPropertyName(v);
50861 renderCell : function(val){
50863 if(val instanceof Date){
50864 rv = this.renderDate(val);
50865 }else if(typeof val == 'boolean'){
50866 rv = this.renderBool(val);
50868 return Roo.util.Format.htmlEncode(rv);
50871 getPropertyName : function(name){
50872 var pn = this.grid.propertyNames;
50873 return pn && pn[name] ? pn[name] : name;
50876 getCellEditor : function(colIndex, rowIndex){
50877 var p = this.store.getProperty(rowIndex);
50878 var n = p.data['name'], val = p.data['value'];
50880 if(typeof(this.grid.customEditors[n]) == 'string'){
50881 return this.editors[this.grid.customEditors[n]];
50883 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50884 return this.grid.customEditors[n];
50886 if(val instanceof Date){
50887 return this.editors['date'];
50888 }else if(typeof val == 'number'){
50889 return this.editors['number'];
50890 }else if(typeof val == 'boolean'){
50891 return this.editors['boolean'];
50893 return this.editors['string'];
50899 * @class Roo.grid.PropertyGrid
50900 * @extends Roo.grid.EditorGrid
50901 * This class represents the interface of a component based property grid control.
50902 * <br><br>Usage:<pre><code>
50903 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50911 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50912 * The container MUST have some type of size defined for the grid to fill. The container will be
50913 * automatically set to position relative if it isn't already.
50914 * @param {Object} config A config object that sets properties on this grid.
50916 Roo.grid.PropertyGrid = function(container, config){
50917 config = config || {};
50918 var store = new Roo.grid.PropertyStore(this);
50919 this.store = store;
50920 var cm = new Roo.grid.PropertyColumnModel(this, store);
50921 store.store.sort('name', 'ASC');
50922 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50925 enableColLock:false,
50926 enableColumnMove:false,
50928 trackMouseOver: false,
50931 this.getGridEl().addClass('x-props-grid');
50932 this.lastEditRow = null;
50933 this.on('columnresize', this.onColumnResize, this);
50936 * @event beforepropertychange
50937 * Fires before a property changes (return false to stop?)
50938 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50939 * @param {String} id Record Id
50940 * @param {String} newval New Value
50941 * @param {String} oldval Old Value
50943 "beforepropertychange": true,
50945 * @event propertychange
50946 * Fires after a property changes
50947 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50948 * @param {String} id Record Id
50949 * @param {String} newval New Value
50950 * @param {String} oldval Old Value
50952 "propertychange": true
50954 this.customEditors = this.customEditors || {};
50956 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50959 * @cfg {Object} customEditors map of colnames=> custom editors.
50960 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50961 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50962 * false disables editing of the field.
50966 * @cfg {Object} propertyNames map of property Names to their displayed value
50969 render : function(){
50970 Roo.grid.PropertyGrid.superclass.render.call(this);
50971 this.autoSize.defer(100, this);
50974 autoSize : function(){
50975 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50977 this.view.fitColumns();
50981 onColumnResize : function(){
50982 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50986 * Sets the data for the Grid
50987 * accepts a Key => Value object of all the elements avaiable.
50988 * @param {Object} data to appear in grid.
50990 setSource : function(source){
50991 this.store.setSource(source);
50995 * Gets all the data from the grid.
50996 * @return {Object} data data stored in grid
50998 getSource : function(){
50999 return this.store.getSource();
51003 * Ext JS Library 1.1.1
51004 * Copyright(c) 2006-2007, Ext JS, LLC.
51006 * Originally Released Under LGPL - original licence link has changed is not relivant.
51009 * <script type="text/javascript">
51013 * @class Roo.LoadMask
51014 * A simple utility class for generically masking elements while loading data. If the element being masked has
51015 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
51016 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
51017 * element's UpdateManager load indicator and will be destroyed after the initial load.
51019 * Create a new LoadMask
51020 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
51021 * @param {Object} config The config object
51023 Roo.LoadMask = function(el, config){
51024 this.el = Roo.get(el);
51025 Roo.apply(this, config);
51027 this.store.on('beforeload', this.onBeforeLoad, this);
51028 this.store.on('load', this.onLoad, this);
51029 this.store.on('loadexception', this.onLoad, this);
51030 this.removeMask = false;
51032 var um = this.el.getUpdateManager();
51033 um.showLoadIndicator = false; // disable the default indicator
51034 um.on('beforeupdate', this.onBeforeLoad, this);
51035 um.on('update', this.onLoad, this);
51036 um.on('failure', this.onLoad, this);
51037 this.removeMask = true;
51041 Roo.LoadMask.prototype = {
51043 * @cfg {Boolean} removeMask
51044 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
51045 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
51048 * @cfg {String} msg
51049 * The text to display in a centered loading message box (defaults to 'Loading...')
51051 msg : 'Loading...',
51053 * @cfg {String} msgCls
51054 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
51056 msgCls : 'x-mask-loading',
51059 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
51065 * Disables the mask to prevent it from being displayed
51067 disable : function(){
51068 this.disabled = true;
51072 * Enables the mask so that it can be displayed
51074 enable : function(){
51075 this.disabled = false;
51079 onLoad : function(){
51080 this.el.unmask(this.removeMask);
51084 onBeforeLoad : function(){
51085 if(!this.disabled){
51086 this.el.mask(this.msg, this.msgCls);
51091 destroy : function(){
51093 this.store.un('beforeload', this.onBeforeLoad, this);
51094 this.store.un('load', this.onLoad, this);
51095 this.store.un('loadexception', this.onLoad, this);
51097 var um = this.el.getUpdateManager();
51098 um.un('beforeupdate', this.onBeforeLoad, this);
51099 um.un('update', this.onLoad, this);
51100 um.un('failure', this.onLoad, this);
51105 * Ext JS Library 1.1.1
51106 * Copyright(c) 2006-2007, Ext JS, LLC.
51108 * Originally Released Under LGPL - original licence link has changed is not relivant.
51111 * <script type="text/javascript">
51113 Roo.XTemplate = function(){
51114 Roo.XTemplate.superclass.constructor.apply(this, arguments);
51117 s = ['<tpl>', s, '</tpl>'].join('');
51119 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
51121 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
51122 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
51123 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
51127 while(m = s.match(re)){
51128 var m2 = m[0].match(nameRe);
51129 var m3 = m[0].match(ifRe);
51130 var m4 = m[0].match(execRe);
51131 var exp = null, fn = null, exec = null;
51132 var name = m2 && m2[1] ? m2[1] : '';
51134 exp = m3 && m3[1] ? m3[1] : null;
51136 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
51140 exp = m4 && m4[1] ? m4[1] : null;
51142 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
51147 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
51148 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
51149 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
51159 s = s.replace(m[0], '{xtpl'+ id + '}');
51162 for(var i = tpls.length-1; i >= 0; --i){
51163 this.compileTpl(tpls[i]);
51165 this.master = tpls[tpls.length-1];
51168 Roo.extend(Roo.XTemplate, Roo.Template, {
51170 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
51172 applySubTemplate : function(id, values, parent){
51173 var t = this.tpls[id];
51174 if(t.test && !t.test.call(this, values, parent)){
51177 if(t.exec && t.exec.call(this, values, parent)){
51180 var vs = t.target ? t.target.call(this, values, parent) : values;
51181 parent = t.target ? values : parent;
51182 if(t.target && vs instanceof Array){
51184 for(var i = 0, len = vs.length; i < len; i++){
51185 buf[buf.length] = t.compiled.call(this, vs[i], parent);
51187 return buf.join('');
51189 return t.compiled.call(this, vs, parent);
51192 compileTpl : function(tpl){
51193 var fm = Roo.util.Format;
51194 var useF = this.disableFormats !== true;
51195 var sep = Roo.isGecko ? "+" : ",";
51196 var fn = function(m, name, format, args){
51197 if(name.substr(0, 4) == 'xtpl'){
51198 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
51201 if(name.indexOf('.') != -1){
51204 v = "values['" + name + "']";
51206 if(format && useF){
51207 args = args ? ',' + args : "";
51208 if(format.substr(0, 5) != "this."){
51209 format = "fm." + format + '(';
51211 format = 'this.call("'+ format.substr(5) + '", ';
51215 args= ''; format = "("+v+" === undefined ? '' : ";
51217 return "'"+ sep + format + v + args + ")"+sep+"'";
51220 // branched to use + in gecko and [].join() in others
51222 body = "tpl.compiled = function(values, parent){ return '" +
51223 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
51226 body = ["tpl.compiled = function(values, parent){ return ['"];
51227 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
51228 body.push("'].join('');};");
51229 body = body.join('');
51231 /** eval:var:zzzzzzz */
51236 applyTemplate : function(values){
51237 return this.master.compiled.call(this, values, {});
51241 apply : function(){
51242 return this.applyTemplate.apply(this, arguments);
51245 compile : function(){return this;}
51248 Roo.XTemplate.from = function(el){
51249 el = Roo.getDom(el);
51250 return new Roo.XTemplate(el.value || el.innerHTML);
51252 * Original code for Roojs - LGPL
51253 * <script type="text/javascript">
51257 * @class Roo.XComponent
51258 * A delayed Element creator...
51259 * Or a way to group chunks of interface together.
51261 * Mypart.xyx = new Roo.XComponent({
51263 parent : 'Mypart.xyz', // empty == document.element.!!
51267 disabled : function() {}
51269 tree : function() { // return an tree of xtype declared components
51273 xtype : 'NestedLayoutPanel',
51280 * It can be used to build a big heiracy, with parent etc.
51281 * or you can just use this to render a single compoent to a dom element
51282 * MYPART.render(Roo.Element | String(id) | dom_element )
51284 * @extends Roo.util.Observable
51286 * @param cfg {Object} configuration of component
51289 Roo.XComponent = function(cfg) {
51290 Roo.apply(this, cfg);
51294 * Fires when this the componnt is built
51295 * @param {Roo.XComponent} c the component
51299 * @event buildcomplete
51300 * Fires on the top level element when all elements have been built
51301 * @param {Roo.XComponent} c the top level component.
51303 'buildcomplete' : true
51307 Roo.XComponent.register(this);
51308 this.modules = false;
51309 this.el = false; // where the layout goes..
51313 Roo.extend(Roo.XComponent, Roo.util.Observable, {
51316 * The created element (with Roo.factory())
51317 * @type {Roo.Layout}
51323 * for BC - use el in new code
51324 * @type {Roo.Layout}
51330 * for BC - use el in new code
51331 * @type {Roo.Layout}
51336 * @cfg {Function|boolean} disabled
51337 * If this module is disabled by some rule, return true from the funtion
51342 * @cfg {String} parent
51343 * Name of parent element which it get xtype added to..
51348 * @cfg {String} order
51349 * Used to set the order in which elements are created (usefull for multiple tabs)
51354 * @cfg {String} name
51355 * String to display while loading.
51359 * @cfg {String} region
51360 * Region to render component to (defaults to center)
51365 * @cfg {Array} items
51366 * A single item array - the first element is the root of the tree..
51367 * It's done this way to stay compatible with the Xtype system...
51374 * render element to dom or tree
51375 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
51378 render : function(el)
51383 if (!el && typeof(m.parent) == 'string' && m.parent[0] == '#') {
51384 // if parent is a '#.....' string, then let's use that..
51385 this.parent = false;
51386 el = Roo.get(m.substr(1));
51388 if (!this.parent) {
51390 el = el ? Roo.get(el) : false;
51392 // it's a top level one..
51394 el : new Roo.BorderLayout(el || document.body, {
51400 tabPosition: 'top',
51401 //resizeTabs: true,
51402 alwaysShowTabs: el ? false : true,
51403 hideTabs: el ? true : false,
51410 var tree = this.tree();
51411 tree.region = tree.region || this.region;
51412 this.el = this.parent.el.addxtype(tree);
51413 this.fireEvent('built', this);
51415 this.panel = this.el;
51416 this.layout = this.panel.layout;
51422 Roo.apply(Roo.XComponent, {
51425 * @property buildCompleted
51426 * True when the builder has completed building the interface.
51429 buildCompleted : false,
51432 * @property topModule
51433 * the upper most module - uses document.element as it's constructor.
51440 * @property modules
51441 * array of modules to be created by registration system.
51442 * @type {Array} of Roo.XComponent
51447 * @property elmodules
51448 * array of modules to be created by which use #ID
51449 * @type {Array} of Roo.XComponent
51456 * Register components to be built later.
51458 * This solves the following issues
51459 * - Building is not done on page load, but after an authentication process has occured.
51460 * - Interface elements are registered on page load
51461 * - Parent Interface elements may not be loaded before child, so this handles that..
51468 module : 'Pman.Tab.projectMgr',
51470 parent : 'Pman.layout',
51471 disabled : false, // or use a function..
51474 * * @param {Object} details about module
51476 register : function(obj) {
51477 this.modules.push(obj);
51481 * convert a string to an object..
51482 * eg. 'AAA.BBB' -> finds AAA.BBB
51486 toObject : function(str)
51488 if (!str || typeof(str) == 'object') {
51495 var ar = str.split('.');
51499 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51501 throw "Module not found : " + str;
51503 Roo.each(ar, function(e) {
51504 if (typeof(o[e]) == 'undefined') {
51505 throw "Module not found : " + str;
51515 * move modules into their correct place in the tree..
51518 preBuild : function ()
51521 Roo.each(this.modules , function (obj)
51523 obj.parent = this.toObject(obj.parent);
51526 this.topModule = obj;
51529 if (typeof(obj.parent) == 'string') {
51530 this.elmodules.push(obj);
51534 if (!obj.parent.modules) {
51535 obj.parent.modules = new Roo.util.MixedCollection(false,
51536 function(o) { return o.order + '' }
51540 obj.parent.modules.add(obj);
51545 * make a list of modules to build.
51546 * @return {Array} list of modules.
51549 buildOrder : function()
51552 var cmp = function(a,b) {
51553 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51555 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
51556 throw "No top level modules to build";
51559 // make a flat list in order of modules to build.
51560 var mods = this.topModule ? [ this.topModule ] : [];
51561 Roo.each(this.elmodules,function(e) { mods.push(e) });
51564 // add modules to their parents..
51565 var addMod = function(m) {
51566 // Roo.debug && Roo.log(m.modKey);
51570 m.modules.keySort('ASC', cmp );
51571 m.modules.each(addMod);
51573 // not sure if this is used any more..
51575 m.finalize.name = m.name + " (clean up) ";
51576 mods.push(m.finalize);
51580 if (this.topModule) {
51581 this.topModule.modules.keySort('ASC', cmp );
51582 this.topModule.modules.each(addMod);
51588 * Build the registered modules.
51589 * @param {Object} parent element.
51590 * @param {Function} optional method to call after module has been added.
51598 var mods = this.buildOrder();
51600 //this.allmods = mods;
51601 //Roo.debug && Roo.log(mods);
51603 if (!mods.length) { // should not happen
51604 throw "NO modules!!!";
51609 // flash it up as modal - so we store the mask!?
51610 Roo.MessageBox.show({ title: 'loading' });
51611 Roo.MessageBox.show({
51612 title: "Please wait...",
51613 msg: "Building Interface...",
51620 var total = mods.length;
51623 var progressRun = function() {
51624 if (!mods.length) {
51625 Roo.debug && Roo.log('hide?');
51626 Roo.MessageBox.hide();
51627 if (_this.topModule) {
51628 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51634 var m = mods.shift();
51637 Roo.debug && Roo.log(m);
51638 // not sure if this is supported any more.. - modules that are are just function
51639 if (typeof(m) == 'function') {
51641 return progressRun.defer(10, _this);
51646 Roo.MessageBox.updateProgress(
51647 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51649 (m.name ? (' - ' + m.name) : '')
51653 // is the module disabled?
51654 var disabled = (typeof(m.disabled) == 'function') ?
51655 m.disabled.call(m.module.disabled) : m.disabled;
51659 return progressRun(); // we do not update the display!
51665 // it's 10 on top level, and 1 on others??? why...
51666 return progressRun.defer(10, _this);
51669 progressRun.defer(1, _this);
51680 //<script type="text/javascript">
51685 * @extends Roo.LayoutDialog
51686 * A generic Login Dialog..... - only one needed in theory!?!?
51688 * Fires XComponent builder on success...
51691 * username,password, lang = for login actions.
51692 * check = 1 for periodic checking that sesion is valid.
51693 * passwordRequest = email request password
51694 * logout = 1 = to logout
51696 * Affects: (this id="????" elements)
51697 * loading (removed) (used to indicate application is loading)
51698 * loading-mask (hides) (used to hide application when it's building loading)
51704 * Myapp.login = Roo.Login({
51720 Roo.Login = function(cfg)
51726 Roo.apply(this,cfg);
51728 Roo.onReady(function() {
51734 Roo.Login.superclass.constructor.call(this, this);
51735 //this.addxtype(this.items[0]);
51741 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51744 * @cfg {String} method
51745 * Method used to query for login details.
51750 * @cfg {String} url
51751 * URL to query login data. - eg. baseURL + '/Login.php'
51757 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51762 * @property checkFails
51763 * Number of times we have attempted to get authentication check, and failed.
51768 * @property intervalID
51769 * The window interval that does the constant login checking.
51775 onLoad : function() // called on page load...
51779 if (Roo.get('loading')) { // clear any loading indicator..
51780 Roo.get('loading').remove();
51783 //this.switchLang('en'); // set the language to english..
51786 success: function(response, opts) { // check successfull...
51788 var res = this.processResponse(response);
51789 this.checkFails =0;
51790 if (!res.success) { // error!
51791 this.checkFails = 5;
51792 //console.log('call failure');
51793 return this.failure(response,opts);
51796 if (!res.data.id) { // id=0 == login failure.
51797 return this.show();
51801 //console.log(success);
51802 this.fillAuth(res.data);
51803 this.checkFails =0;
51804 Roo.XComponent.build();
51806 failure : this.show
51812 check: function(cfg) // called every so often to refresh cookie etc..
51814 if (cfg.again) { // could be undefined..
51817 this.checkFails = 0;
51820 if (this.sending) {
51821 if ( this.checkFails > 4) {
51822 Roo.MessageBox.alert("Error",
51823 "Error getting authentication status. - try reloading, or wait a while", function() {
51824 _this.sending = false;
51829 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51832 this.sending = true;
51839 method: this.method,
51840 success: cfg.success || this.success,
51841 failure : cfg.failure || this.failure,
51851 window.onbeforeunload = function() { }; // false does not work for IE..
51861 failure : function() {
51862 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51863 document.location = document.location.toString() + '?ts=' + Math.random();
51867 success : function() {
51868 _this.user = false;
51869 this.checkFails =0;
51871 document.location = document.location.toString() + '?ts=' + Math.random();
51878 processResponse : function (response)
51882 res = Roo.decode(response.responseText);
51884 if (typeof(res) != 'object') {
51885 res = { success : false, errorMsg : res, errors : true };
51887 if (typeof(res.success) == 'undefined') {
51888 res.success = false;
51892 res = { success : false, errorMsg : response.responseText, errors : true };
51897 success : function(response, opts) // check successfull...
51899 this.sending = false;
51900 var res = this.processResponse(response);
51901 if (!res.success) {
51902 return this.failure(response, opts);
51904 if (!res.data || !res.data.id) {
51905 return this.failure(response,opts);
51907 //console.log(res);
51908 this.fillAuth(res.data);
51910 this.checkFails =0;
51915 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51917 this.authUser = -1;
51918 this.sending = false;
51919 var res = this.processResponse(response);
51920 //console.log(res);
51921 if ( this.checkFails > 2) {
51923 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51924 "Error getting authentication status. - try reloading");
51927 opts.callCfg.again = true;
51928 this.check.defer(1000, this, [ opts.callCfg ]);
51934 fillAuth: function(au) {
51935 this.startAuthCheck();
51936 this.authUserId = au.id;
51937 this.authUser = au;
51938 this.lastChecked = new Date();
51939 this.fireEvent('refreshed', au);
51940 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51941 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51942 au.lang = au.lang || 'en';
51943 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51944 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51945 this.switchLang(au.lang );
51948 // open system... - -on setyp..
51949 if (this.authUserId < 0) {
51950 Roo.MessageBox.alert("Warning",
51951 "This is an open system - please set up a admin user with a password.");
51954 //Pman.onload(); // which should do nothing if it's a re-auth result...
51959 startAuthCheck : function() // starter for timeout checking..
51961 if (this.intervalID) { // timer already in place...
51965 this.intervalID = window.setInterval(function() {
51966 _this.check(false);
51967 }, 120000); // every 120 secs = 2mins..
51973 switchLang : function (lang)
51975 _T = typeof(_T) == 'undefined' ? false : _T;
51976 if (!_T || !lang.length) {
51980 if (!_T && lang != 'en') {
51981 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51985 if (typeof(_T.en) == 'undefined') {
51987 Roo.apply(_T.en, _T);
51990 if (typeof(_T[lang]) == 'undefined') {
51991 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51996 Roo.apply(_T, _T[lang]);
51997 // just need to set the text values for everything...
51999 /* this will not work ...
52003 function formLabel(name, val) {
52004 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
52007 formLabel('password', "Password"+':');
52008 formLabel('username', "Email Address"+':');
52009 formLabel('lang', "Language"+':');
52010 this.dialog.setTitle("Login");
52011 this.dialog.buttons[0].setText("Forgot Password");
52012 this.dialog.buttons[1].setText("Login");
52031 collapsible: false,
52033 center: { // needed??
52036 // tabPosition: 'top',
52039 alwaysShowTabs: false
52043 show : function(dlg)
52045 //console.log(this);
52046 this.form = this.layout.getRegion('center').activePanel.form;
52047 this.form.dialog = dlg;
52048 this.buttons[0].form = this.form;
52049 this.buttons[0].dialog = dlg;
52050 this.buttons[1].form = this.form;
52051 this.buttons[1].dialog = dlg;
52053 //this.resizeToLogo.defer(1000,this);
52054 // this is all related to resizing for logos..
52055 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
52057 // this.resizeToLogo.defer(1000,this);
52060 //var w = Ext.lib.Dom.getViewWidth() - 100;
52061 //var h = Ext.lib.Dom.getViewHeight() - 100;
52062 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
52064 if (this.disabled) {
52069 if (this.user.id < 0) { // used for inital setup situations.
52073 if (this.intervalID) {
52074 // remove the timer
52075 window.clearInterval(this.intervalID);
52076 this.intervalID = false;
52080 if (Roo.get('loading')) {
52081 Roo.get('loading').remove();
52083 if (Roo.get('loading-mask')) {
52084 Roo.get('loading-mask').hide();
52087 //incomming._node = tnode;
52089 //this.dialog.modal = !modal;
52090 //this.dialog.show();
52094 this.form.setValues({
52095 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
52096 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
52099 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
52100 if (this.form.findField('username').getValue().length > 0 ){
52101 this.form.findField('password').focus();
52103 this.form.findField('username').focus();
52111 xtype : 'ContentPanel',
52123 style : 'margin: 10px;',
52126 actionfailed : function(f, act) {
52127 // form can return { errors: .... }
52129 //act.result.errors // invalid form element list...
52130 //act.result.errorMsg// invalid form element list...
52132 this.dialog.el.unmask();
52133 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
52134 "Login failed - communication error - try again.");
52137 actioncomplete: function(re, act) {
52139 Roo.state.Manager.set(
52140 this.dialog.realm + '.username',
52141 this.findField('username').getValue()
52143 Roo.state.Manager.set(
52144 this.dialog.realm + '.lang',
52145 this.findField('lang').getValue()
52148 this.dialog.fillAuth(act.result.data);
52150 this.dialog.hide();
52152 if (Roo.get('loading-mask')) {
52153 Roo.get('loading-mask').show();
52155 Roo.XComponent.build();
52163 xtype : 'TextField',
52165 fieldLabel: "Email Address",
52168 autoCreate : {tag: "input", type: "text", size: "20"}
52171 xtype : 'TextField',
52173 fieldLabel: "Password",
52174 inputType: 'password',
52177 autoCreate : {tag: "input", type: "text", size: "20"},
52179 specialkey : function(e,ev) {
52180 if (ev.keyCode == 13) {
52181 this.form.dialog.el.mask("Logging in");
52182 this.form.doAction('submit', {
52183 url: this.form.dialog.url,
52184 method: this.form.dialog.method
52191 xtype : 'ComboBox',
52193 fieldLabel: "Language",
52196 xtype : 'SimpleStore',
52197 fields: ['lang', 'ldisp'],
52199 [ 'en', 'English' ],
52200 [ 'zh_HK' , '\u7E41\u4E2D' ],
52201 [ 'zh_CN', '\u7C21\u4E2D' ]
52205 valueField : 'lang',
52206 hiddenName: 'lang',
52208 displayField:'ldisp',
52212 triggerAction: 'all',
52213 emptyText:'Select a Language...',
52214 selectOnFocus:true,
52216 select : function(cb, rec, ix) {
52217 this.form.switchLang(rec.data.lang);
52233 text : "Forgot Password",
52235 click : function() {
52236 //console.log(this);
52237 var n = this.form.findField('username').getValue();
52239 Roo.MessageBox.alert("Error", "Fill in your email address");
52243 url: this.dialog.url,
52247 method: this.dialog.method,
52248 success: function(response, opts) { // check successfull...
52250 var res = this.dialog.processResponse(response);
52251 if (!res.success) { // error!
52252 Roo.MessageBox.alert("Error" ,
52253 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
52256 Roo.MessageBox.alert("Notice" ,
52257 "Please check you email for the Password Reset message");
52259 failure : function() {
52260 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
52273 click : function () {
52275 this.dialog.el.mask("Logging in");
52276 this.form.doAction('submit', {
52277 url: this.dialog.url,
52278 method: this.dialog.method