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 = {
19171 if(config && config.data){
19172 this.inlineData = config.data;
19173 delete config.data;
19176 Roo.apply(this, config);
19178 if(this.reader){ // reader passed
19179 this.reader = Roo.factory(this.reader, Roo.data);
19180 this.reader.xmodule = this.xmodule || false;
19181 if(!this.recordType){
19182 this.recordType = this.reader.recordType;
19184 if(this.reader.onMetaChange){
19185 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19189 if(this.recordType){
19190 this.fields = this.recordType.prototype.fields;
19192 this.modified = [];
19196 * @event datachanged
19197 * Fires when the data cache has changed, and a widget which is using this Store
19198 * as a Record cache should refresh its view.
19199 * @param {Store} this
19201 datachanged : true,
19203 * @event metachange
19204 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19205 * @param {Store} this
19206 * @param {Object} meta The JSON metadata
19211 * Fires when Records have been added to the Store
19212 * @param {Store} this
19213 * @param {Roo.data.Record[]} records The array of Records added
19214 * @param {Number} index The index at which the record(s) were added
19219 * Fires when a Record has been removed from the Store
19220 * @param {Store} this
19221 * @param {Roo.data.Record} record The Record that was removed
19222 * @param {Number} index The index at which the record was removed
19227 * Fires when a Record has been updated
19228 * @param {Store} this
19229 * @param {Roo.data.Record} record The Record that was updated
19230 * @param {String} operation The update operation being performed. Value may be one of:
19232 Roo.data.Record.EDIT
19233 Roo.data.Record.REJECT
19234 Roo.data.Record.COMMIT
19240 * Fires when the data cache has been cleared.
19241 * @param {Store} this
19245 * @event beforeload
19246 * Fires before a request is made for a new data object. If the beforeload handler returns false
19247 * the load action will be canceled.
19248 * @param {Store} this
19249 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19254 * Fires after a new set of Records has been loaded.
19255 * @param {Store} this
19256 * @param {Roo.data.Record[]} records The Records that were loaded
19257 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19261 * @event loadexception
19262 * Fires if an exception occurs in the Proxy during loading.
19263 * Called with the signature of the Proxy's "loadexception" event.
19264 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19267 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19268 * @param {Object} load options
19269 * @param {Object} jsonData from your request (normally this contains the Exception)
19271 loadexception : true
19275 this.proxy = Roo.factory(this.proxy, Roo.data);
19276 this.proxy.xmodule = this.xmodule || false;
19277 this.relayEvents(this.proxy, ["loadexception"]);
19279 this.sortToggle = {};
19281 Roo.data.Store.superclass.constructor.call(this);
19283 if(this.inlineData){
19284 this.loadData(this.inlineData);
19285 delete this.inlineData;
19288 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19290 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19291 * without a remote query - used by combo/forms at present.
19295 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19298 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19301 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19302 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19305 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19306 * on any HTTP request
19309 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19312 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19313 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19315 remoteSort : false,
19318 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19319 * loaded or when a record is removed. (defaults to false).
19321 pruneModifiedRecords : false,
19324 lastOptions : null,
19327 * Add Records to the Store and fires the add event.
19328 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19330 add : function(records){
19331 records = [].concat(records);
19332 for(var i = 0, len = records.length; i < len; i++){
19333 records[i].join(this);
19335 var index = this.data.length;
19336 this.data.addAll(records);
19337 this.fireEvent("add", this, records, index);
19341 * Remove a Record from the Store and fires the remove event.
19342 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19344 remove : function(record){
19345 var index = this.data.indexOf(record);
19346 this.data.removeAt(index);
19347 if(this.pruneModifiedRecords){
19348 this.modified.remove(record);
19350 this.fireEvent("remove", this, record, index);
19354 * Remove all Records from the Store and fires the clear event.
19356 removeAll : function(){
19358 if(this.pruneModifiedRecords){
19359 this.modified = [];
19361 this.fireEvent("clear", this);
19365 * Inserts Records to the Store at the given index and fires the add event.
19366 * @param {Number} index The start index at which to insert the passed Records.
19367 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19369 insert : function(index, records){
19370 records = [].concat(records);
19371 for(var i = 0, len = records.length; i < len; i++){
19372 this.data.insert(index, records[i]);
19373 records[i].join(this);
19375 this.fireEvent("add", this, records, index);
19379 * Get the index within the cache of the passed Record.
19380 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19381 * @return {Number} The index of the passed Record. Returns -1 if not found.
19383 indexOf : function(record){
19384 return this.data.indexOf(record);
19388 * Get the index within the cache of the Record with the passed id.
19389 * @param {String} id The id of the Record to find.
19390 * @return {Number} The index of the Record. Returns -1 if not found.
19392 indexOfId : function(id){
19393 return this.data.indexOfKey(id);
19397 * Get the Record with the specified id.
19398 * @param {String} id The id of the Record to find.
19399 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19401 getById : function(id){
19402 return this.data.key(id);
19406 * Get the Record at the specified index.
19407 * @param {Number} index The index of the Record to find.
19408 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19410 getAt : function(index){
19411 return this.data.itemAt(index);
19415 * Returns a range of Records between specified indices.
19416 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19417 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19418 * @return {Roo.data.Record[]} An array of Records
19420 getRange : function(start, end){
19421 return this.data.getRange(start, end);
19425 storeOptions : function(o){
19426 o = Roo.apply({}, o);
19429 this.lastOptions = o;
19433 * Loads the Record cache from the configured Proxy using the configured Reader.
19435 * If using remote paging, then the first load call must specify the <em>start</em>
19436 * and <em>limit</em> properties in the options.params property to establish the initial
19437 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19439 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19440 * and this call will return before the new data has been loaded. Perform any post-processing
19441 * in a callback function, or in a "load" event handler.</strong>
19443 * @param {Object} options An object containing properties which control loading options:<ul>
19444 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19445 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19446 * passed the following arguments:<ul>
19447 * <li>r : Roo.data.Record[]</li>
19448 * <li>options: Options object from the load call</li>
19449 * <li>success: Boolean success indicator</li></ul></li>
19450 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19451 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19454 load : function(options){
19455 options = options || {};
19456 if(this.fireEvent("beforeload", this, options) !== false){
19457 this.storeOptions(options);
19458 var p = Roo.apply(options.params || {}, this.baseParams);
19459 // if meta was not loaded from remote source.. try requesting it.
19460 if (!this.reader.metaFromRemote) {
19461 p._requestMeta = 1;
19463 if(this.sortInfo && this.remoteSort){
19464 var pn = this.paramNames;
19465 p[pn["sort"]] = this.sortInfo.field;
19466 p[pn["dir"]] = this.sortInfo.direction;
19468 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19473 * Reloads the Record cache from the configured Proxy using the configured Reader and
19474 * the options from the last load operation performed.
19475 * @param {Object} options (optional) An object containing properties which may override the options
19476 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19477 * the most recently used options are reused).
19479 reload : function(options){
19480 this.load(Roo.applyIf(options||{}, this.lastOptions));
19484 // Called as a callback by the Reader during a load operation.
19485 loadRecords : function(o, options, success){
19486 if(!o || success === false){
19487 if(success !== false){
19488 this.fireEvent("load", this, [], options);
19490 if(options.callback){
19491 options.callback.call(options.scope || this, [], options, false);
19495 // if data returned failure - throw an exception.
19496 if (o.success === false) {
19497 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19500 var r = o.records, t = o.totalRecords || r.length;
19501 if(!options || options.add !== true){
19502 if(this.pruneModifiedRecords){
19503 this.modified = [];
19505 for(var i = 0, len = r.length; i < len; i++){
19509 this.data = this.snapshot;
19510 delete this.snapshot;
19513 this.data.addAll(r);
19514 this.totalLength = t;
19516 this.fireEvent("datachanged", this);
19518 this.totalLength = Math.max(t, this.data.length+r.length);
19521 this.fireEvent("load", this, r, options);
19522 if(options.callback){
19523 options.callback.call(options.scope || this, r, options, true);
19528 * Loads data from a passed data block. A Reader which understands the format of the data
19529 * must have been configured in the constructor.
19530 * @param {Object} data The data block from which to read the Records. The format of the data expected
19531 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19532 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19534 loadData : function(o, append){
19535 var r = this.reader.readRecords(o);
19536 this.loadRecords(r, {add: append}, true);
19540 * Gets the number of cached records.
19542 * <em>If using paging, this may not be the total size of the dataset. If the data object
19543 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19544 * the data set size</em>
19546 getCount : function(){
19547 return this.data.length || 0;
19551 * Gets the total number of records in the dataset as returned by the server.
19553 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19554 * the dataset size</em>
19556 getTotalCount : function(){
19557 return this.totalLength || 0;
19561 * Returns the sort state of the Store as an object with two properties:
19563 field {String} The name of the field by which the Records are sorted
19564 direction {String} The sort order, "ASC" or "DESC"
19567 getSortState : function(){
19568 return this.sortInfo;
19572 applySort : function(){
19573 if(this.sortInfo && !this.remoteSort){
19574 var s = this.sortInfo, f = s.field;
19575 var st = this.fields.get(f).sortType;
19576 var fn = function(r1, r2){
19577 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19578 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19580 this.data.sort(s.direction, fn);
19581 if(this.snapshot && this.snapshot != this.data){
19582 this.snapshot.sort(s.direction, fn);
19588 * Sets the default sort column and order to be used by the next load operation.
19589 * @param {String} fieldName The name of the field to sort by.
19590 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19592 setDefaultSort : function(field, dir){
19593 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19597 * Sort the Records.
19598 * If remote sorting is used, the sort is performed on the server, and the cache is
19599 * reloaded. If local sorting is used, the cache is sorted internally.
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 sort : function(fieldName, dir){
19604 var f = this.fields.get(fieldName);
19606 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19607 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19612 this.sortToggle[f.name] = dir;
19613 this.sortInfo = {field: f.name, direction: dir};
19614 if(!this.remoteSort){
19616 this.fireEvent("datachanged", this);
19618 this.load(this.lastOptions);
19623 * Calls the specified function for each of the Records in the cache.
19624 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19625 * Returning <em>false</em> aborts and exits the iteration.
19626 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19628 each : function(fn, scope){
19629 this.data.each(fn, scope);
19633 * Gets all records modified since the last commit. Modified records are persisted across load operations
19634 * (e.g., during paging).
19635 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19637 getModifiedRecords : function(){
19638 return this.modified;
19642 createFilterFn : function(property, value, anyMatch){
19643 if(!value.exec){ // not a regex
19644 value = String(value);
19645 if(value.length == 0){
19648 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19650 return function(r){
19651 return value.test(r.data[property]);
19656 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19657 * @param {String} property A field on your records
19658 * @param {Number} start The record index to start at (defaults to 0)
19659 * @param {Number} end The last record index to include (defaults to length - 1)
19660 * @return {Number} The sum
19662 sum : function(property, start, end){
19663 var rs = this.data.items, v = 0;
19664 start = start || 0;
19665 end = (end || end === 0) ? end : rs.length-1;
19667 for(var i = start; i <= end; i++){
19668 v += (rs[i].data[property] || 0);
19674 * Filter the records by a specified property.
19675 * @param {String} field A field on your records
19676 * @param {String/RegExp} value Either a string that the field
19677 * should start with or a RegExp to test against the field
19678 * @param {Boolean} anyMatch True to match any part not just the beginning
19680 filter : function(property, value, anyMatch){
19681 var fn = this.createFilterFn(property, value, anyMatch);
19682 return fn ? this.filterBy(fn) : this.clearFilter();
19686 * Filter by a function. The specified function will be called with each
19687 * record in this data source. If the function returns true the record is included,
19688 * otherwise it is filtered.
19689 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19690 * @param {Object} scope (optional) The scope of the function (defaults to this)
19692 filterBy : function(fn, scope){
19693 this.snapshot = this.snapshot || this.data;
19694 this.data = this.queryBy(fn, scope||this);
19695 this.fireEvent("datachanged", this);
19699 * Query the records by a specified property.
19700 * @param {String} field A field on your records
19701 * @param {String/RegExp} value Either a string that the field
19702 * should start with or a RegExp to test against the field
19703 * @param {Boolean} anyMatch True to match any part not just the beginning
19704 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19706 query : function(property, value, anyMatch){
19707 var fn = this.createFilterFn(property, value, anyMatch);
19708 return fn ? this.queryBy(fn) : this.data.clone();
19712 * Query by a function. The specified function will be called with each
19713 * record in this data source. If the function returns true the record is included
19715 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19716 * @param {Object} scope (optional) The scope of the function (defaults to this)
19717 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19719 queryBy : function(fn, scope){
19720 var data = this.snapshot || this.data;
19721 return data.filterBy(fn, scope||this);
19725 * Collects unique values for a particular dataIndex from this store.
19726 * @param {String} dataIndex The property to collect
19727 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19728 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19729 * @return {Array} An array of the unique values
19731 collect : function(dataIndex, allowNull, bypassFilter){
19732 var d = (bypassFilter === true && this.snapshot) ?
19733 this.snapshot.items : this.data.items;
19734 var v, sv, r = [], l = {};
19735 for(var i = 0, len = d.length; i < len; i++){
19736 v = d[i].data[dataIndex];
19738 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19747 * Revert to a view of the Record cache with no filtering applied.
19748 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19750 clearFilter : function(suppressEvent){
19751 if(this.snapshot && this.snapshot != this.data){
19752 this.data = this.snapshot;
19753 delete this.snapshot;
19754 if(suppressEvent !== true){
19755 this.fireEvent("datachanged", this);
19761 afterEdit : function(record){
19762 if(this.modified.indexOf(record) == -1){
19763 this.modified.push(record);
19765 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19769 afterReject : function(record){
19770 this.modified.remove(record);
19771 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19775 afterCommit : function(record){
19776 this.modified.remove(record);
19777 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19781 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19782 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19784 commitChanges : function(){
19785 var m = this.modified.slice(0);
19786 this.modified = [];
19787 for(var i = 0, len = m.length; i < len; i++){
19793 * Cancel outstanding changes on all changed records.
19795 rejectChanges : function(){
19796 var m = this.modified.slice(0);
19797 this.modified = [];
19798 for(var i = 0, len = m.length; i < len; i++){
19803 onMetaChange : function(meta, rtype, o){
19804 this.recordType = rtype;
19805 this.fields = rtype.prototype.fields;
19806 delete this.snapshot;
19807 this.sortInfo = meta.sortInfo || this.sortInfo;
19808 this.modified = [];
19809 this.fireEvent('metachange', this, this.reader.meta);
19813 * Ext JS Library 1.1.1
19814 * Copyright(c) 2006-2007, Ext JS, LLC.
19816 * Originally Released Under LGPL - original licence link has changed is not relivant.
19819 * <script type="text/javascript">
19823 * @class Roo.data.SimpleStore
19824 * @extends Roo.data.Store
19825 * Small helper class to make creating Stores from Array data easier.
19826 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19827 * @cfg {Array} fields An array of field definition objects, or field name strings.
19828 * @cfg {Array} data The multi-dimensional array of data
19830 * @param {Object} config
19832 Roo.data.SimpleStore = function(config){
19833 Roo.data.SimpleStore.superclass.constructor.call(this, {
19835 reader: new Roo.data.ArrayReader({
19838 Roo.data.Record.create(config.fields)
19840 proxy : new Roo.data.MemoryProxy(config.data)
19844 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19846 * Ext JS Library 1.1.1
19847 * Copyright(c) 2006-2007, Ext JS, LLC.
19849 * Originally Released Under LGPL - original licence link has changed is not relivant.
19852 * <script type="text/javascript">
19857 * @extends Roo.data.Store
19858 * @class Roo.data.JsonStore
19859 * Small helper class to make creating Stores for JSON data easier. <br/>
19861 var store = new Roo.data.JsonStore({
19862 url: 'get-images.php',
19864 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19867 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19868 * JsonReader and HttpProxy (unless inline data is provided).</b>
19869 * @cfg {Array} fields An array of field definition objects, or field name strings.
19871 * @param {Object} config
19873 Roo.data.JsonStore = function(c){
19874 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19875 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19876 reader: new Roo.data.JsonReader(c, c.fields)
19879 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19881 * Ext JS Library 1.1.1
19882 * Copyright(c) 2006-2007, Ext JS, LLC.
19884 * Originally Released Under LGPL - original licence link has changed is not relivant.
19887 * <script type="text/javascript">
19891 Roo.data.Field = function(config){
19892 if(typeof config == "string"){
19893 config = {name: config};
19895 Roo.apply(this, config);
19898 this.type = "auto";
19901 var st = Roo.data.SortTypes;
19902 // named sortTypes are supported, here we look them up
19903 if(typeof this.sortType == "string"){
19904 this.sortType = st[this.sortType];
19907 // set default sortType for strings and dates
19908 if(!this.sortType){
19911 this.sortType = st.asUCString;
19914 this.sortType = st.asDate;
19917 this.sortType = st.none;
19922 var stripRe = /[\$,%]/g;
19924 // prebuilt conversion function for this field, instead of
19925 // switching every time we're reading a value
19927 var cv, dateFormat = this.dateFormat;
19932 cv = function(v){ return v; };
19935 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19939 return v !== undefined && v !== null && v !== '' ?
19940 parseInt(String(v).replace(stripRe, ""), 10) : '';
19945 return v !== undefined && v !== null && v !== '' ?
19946 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19951 cv = function(v){ return v === true || v === "true" || v == 1; };
19958 if(v instanceof Date){
19962 if(dateFormat == "timestamp"){
19963 return new Date(v*1000);
19965 return Date.parseDate(v, dateFormat);
19967 var parsed = Date.parse(v);
19968 return parsed ? new Date(parsed) : null;
19977 Roo.data.Field.prototype = {
19985 * Ext JS Library 1.1.1
19986 * Copyright(c) 2006-2007, Ext JS, LLC.
19988 * Originally Released Under LGPL - original licence link has changed is not relivant.
19991 * <script type="text/javascript">
19994 // Base class for reading structured data from a data source. This class is intended to be
19995 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19998 * @class Roo.data.DataReader
19999 * Base class for reading structured data from a data source. This class is intended to be
20000 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20003 Roo.data.DataReader = function(meta, recordType){
20007 this.recordType = recordType instanceof Array ?
20008 Roo.data.Record.create(recordType) : recordType;
20011 Roo.data.DataReader.prototype = {
20013 * Create an empty record
20014 * @param {Object} data (optional) - overlay some values
20015 * @return {Roo.data.Record} record created.
20017 newRow : function(d) {
20019 this.recordType.prototype.fields.each(function(c) {
20021 case 'int' : da[c.name] = 0; break;
20022 case 'date' : da[c.name] = new Date(); break;
20023 case 'float' : da[c.name] = 0.0; break;
20024 case 'boolean' : da[c.name] = false; break;
20025 default : da[c.name] = ""; break;
20029 return new this.recordType(Roo.apply(da, d));
20034 * Ext JS Library 1.1.1
20035 * Copyright(c) 2006-2007, Ext JS, LLC.
20037 * Originally Released Under LGPL - original licence link has changed is not relivant.
20040 * <script type="text/javascript">
20044 * @class Roo.data.DataProxy
20045 * @extends Roo.data.Observable
20046 * This class is an abstract base class for implementations which provide retrieval of
20047 * unformatted data objects.<br>
20049 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20050 * (of the appropriate type which knows how to parse the data object) to provide a block of
20051 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20053 * Custom implementations must implement the load method as described in
20054 * {@link Roo.data.HttpProxy#load}.
20056 Roo.data.DataProxy = function(){
20059 * @event beforeload
20060 * Fires before a network request is made to retrieve a data object.
20061 * @param {Object} This DataProxy object.
20062 * @param {Object} params The params parameter to the load function.
20067 * Fires before the load method's callback is called.
20068 * @param {Object} This DataProxy object.
20069 * @param {Object} o The data object.
20070 * @param {Object} arg The callback argument object passed to the load function.
20074 * @event loadexception
20075 * Fires if an Exception occurs during data retrieval.
20076 * @param {Object} This DataProxy object.
20077 * @param {Object} o The data object.
20078 * @param {Object} arg The callback argument object passed to the load function.
20079 * @param {Object} e The Exception.
20081 loadexception : true
20083 Roo.data.DataProxy.superclass.constructor.call(this);
20086 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20089 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20093 * Ext JS Library 1.1.1
20094 * Copyright(c) 2006-2007, Ext JS, LLC.
20096 * Originally Released Under LGPL - original licence link has changed is not relivant.
20099 * <script type="text/javascript">
20102 * @class Roo.data.MemoryProxy
20103 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20104 * to the Reader when its load method is called.
20106 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20108 Roo.data.MemoryProxy = function(data){
20112 Roo.data.MemoryProxy.superclass.constructor.call(this);
20116 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20118 * Load data from the requested source (in this case an in-memory
20119 * data object passed to the constructor), read the data object into
20120 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20121 * process that block using the passed callback.
20122 * @param {Object} params This parameter is not used by the MemoryProxy class.
20123 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20124 * object into a block of Roo.data.Records.
20125 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20126 * The function must be passed <ul>
20127 * <li>The Record block object</li>
20128 * <li>The "arg" argument from the load function</li>
20129 * <li>A boolean success indicator</li>
20131 * @param {Object} scope The scope in which to call the callback
20132 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20134 load : function(params, reader, callback, scope, arg){
20135 params = params || {};
20138 result = reader.readRecords(this.data);
20140 this.fireEvent("loadexception", this, arg, null, e);
20141 callback.call(scope, null, arg, false);
20144 callback.call(scope, result, arg, true);
20148 update : function(params, records){
20153 * Ext JS Library 1.1.1
20154 * Copyright(c) 2006-2007, Ext JS, LLC.
20156 * Originally Released Under LGPL - original licence link has changed is not relivant.
20159 * <script type="text/javascript">
20162 * @class Roo.data.HttpProxy
20163 * @extends Roo.data.DataProxy
20164 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20165 * configured to reference a certain URL.<br><br>
20167 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20168 * from which the running page was served.<br><br>
20170 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20172 * Be aware that to enable the browser to parse an XML document, the server must set
20173 * the Content-Type header in the HTTP response to "text/xml".
20175 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20176 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20177 * will be used to make the request.
20179 Roo.data.HttpProxy = function(conn){
20180 Roo.data.HttpProxy.superclass.constructor.call(this);
20181 // is conn a conn config or a real conn?
20183 this.useAjax = !conn || !conn.events;
20187 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20188 // thse are take from connection...
20191 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20194 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20195 * extra parameters to each request made by this object. (defaults to undefined)
20198 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20199 * to each request made by this object. (defaults to undefined)
20202 * @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)
20205 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20208 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20214 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20218 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20219 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20220 * a finer-grained basis than the DataProxy events.
20222 getConnection : function(){
20223 return this.useAjax ? Roo.Ajax : this.conn;
20227 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20228 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20229 * process that block using the passed callback.
20230 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20231 * for the request to the remote server.
20232 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20233 * object into a block of Roo.data.Records.
20234 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20235 * The function must be passed <ul>
20236 * <li>The Record block object</li>
20237 * <li>The "arg" argument from the load function</li>
20238 * <li>A boolean success indicator</li>
20240 * @param {Object} scope The scope in which to call the callback
20241 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20243 load : function(params, reader, callback, scope, arg){
20244 if(this.fireEvent("beforeload", this, params) !== false){
20246 params : params || {},
20248 callback : callback,
20253 callback : this.loadResponse,
20257 Roo.applyIf(o, this.conn);
20258 if(this.activeRequest){
20259 Roo.Ajax.abort(this.activeRequest);
20261 this.activeRequest = Roo.Ajax.request(o);
20263 this.conn.request(o);
20266 callback.call(scope||this, null, arg, false);
20271 loadResponse : function(o, success, response){
20272 delete this.activeRequest;
20274 this.fireEvent("loadexception", this, o, response);
20275 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20280 result = o.reader.read(response);
20282 this.fireEvent("loadexception", this, o, response, e);
20283 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20287 this.fireEvent("load", this, o, o.request.arg);
20288 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20292 update : function(dataSet){
20297 updateResponse : function(dataSet){
20302 * Ext JS Library 1.1.1
20303 * Copyright(c) 2006-2007, Ext JS, LLC.
20305 * Originally Released Under LGPL - original licence link has changed is not relivant.
20308 * <script type="text/javascript">
20312 * @class Roo.data.ScriptTagProxy
20313 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20314 * other than the originating domain of the running page.<br><br>
20316 * <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
20317 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20319 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20320 * source code that is used as the source inside a <script> tag.<br><br>
20322 * In order for the browser to process the returned data, the server must wrap the data object
20323 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20324 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20325 * depending on whether the callback name was passed:
20328 boolean scriptTag = false;
20329 String cb = request.getParameter("callback");
20332 response.setContentType("text/javascript");
20334 response.setContentType("application/x-json");
20336 Writer out = response.getWriter();
20338 out.write(cb + "(");
20340 out.print(dataBlock.toJsonString());
20347 * @param {Object} config A configuration object.
20349 Roo.data.ScriptTagProxy = function(config){
20350 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20351 Roo.apply(this, config);
20352 this.head = document.getElementsByTagName("head")[0];
20355 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20357 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20359 * @cfg {String} url The URL from which to request the data object.
20362 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20366 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20367 * the server the name of the callback function set up by the load call to process the returned data object.
20368 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20369 * javascript output which calls this named function passing the data object as its only parameter.
20371 callbackParam : "callback",
20373 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20374 * name to the request.
20379 * Load data from the configured URL, read the data object into
20380 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20381 * process that block using the passed callback.
20382 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20383 * for the request to the remote server.
20384 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20385 * object into a block of Roo.data.Records.
20386 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20387 * The function must be passed <ul>
20388 * <li>The Record block object</li>
20389 * <li>The "arg" argument from the load function</li>
20390 * <li>A boolean success indicator</li>
20392 * @param {Object} scope The scope in which to call the callback
20393 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20395 load : function(params, reader, callback, scope, arg){
20396 if(this.fireEvent("beforeload", this, params) !== false){
20398 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20400 var url = this.url;
20401 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20403 url += "&_dc=" + (new Date().getTime());
20405 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20408 cb : "stcCallback"+transId,
20409 scriptId : "stcScript"+transId,
20413 callback : callback,
20419 window[trans.cb] = function(o){
20420 conn.handleResponse(o, trans);
20423 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20425 if(this.autoAbort !== false){
20429 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20431 var script = document.createElement("script");
20432 script.setAttribute("src", url);
20433 script.setAttribute("type", "text/javascript");
20434 script.setAttribute("id", trans.scriptId);
20435 this.head.appendChild(script);
20437 this.trans = trans;
20439 callback.call(scope||this, null, arg, false);
20444 isLoading : function(){
20445 return this.trans ? true : false;
20449 * Abort the current server request.
20451 abort : function(){
20452 if(this.isLoading()){
20453 this.destroyTrans(this.trans);
20458 destroyTrans : function(trans, isLoaded){
20459 this.head.removeChild(document.getElementById(trans.scriptId));
20460 clearTimeout(trans.timeoutId);
20462 window[trans.cb] = undefined;
20464 delete window[trans.cb];
20467 // if hasn't been loaded, wait for load to remove it to prevent script error
20468 window[trans.cb] = function(){
20469 window[trans.cb] = undefined;
20471 delete window[trans.cb];
20478 handleResponse : function(o, trans){
20479 this.trans = false;
20480 this.destroyTrans(trans, true);
20483 result = trans.reader.readRecords(o);
20485 this.fireEvent("loadexception", this, o, trans.arg, e);
20486 trans.callback.call(trans.scope||window, null, trans.arg, false);
20489 this.fireEvent("load", this, o, trans.arg);
20490 trans.callback.call(trans.scope||window, result, trans.arg, true);
20494 handleFailure : function(trans){
20495 this.trans = false;
20496 this.destroyTrans(trans, false);
20497 this.fireEvent("loadexception", this, null, trans.arg);
20498 trans.callback.call(trans.scope||window, null, trans.arg, false);
20502 * Ext JS Library 1.1.1
20503 * Copyright(c) 2006-2007, Ext JS, LLC.
20505 * Originally Released Under LGPL - original licence link has changed is not relivant.
20508 * <script type="text/javascript">
20512 * @class Roo.data.JsonReader
20513 * @extends Roo.data.DataReader
20514 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20515 * based on mappings in a provided Roo.data.Record constructor.
20517 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20518 * in the reply previously.
20523 var RecordDef = Roo.data.Record.create([
20524 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20525 {name: 'occupation'} // This field will use "occupation" as the mapping.
20527 var myReader = new Roo.data.JsonReader({
20528 totalProperty: "results", // The property which contains the total dataset size (optional)
20529 root: "rows", // The property which contains an Array of row objects
20530 id: "id" // The property within each row object that provides an ID for the record (optional)
20534 * This would consume a JSON file like this:
20536 { 'results': 2, 'rows': [
20537 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20538 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20541 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20542 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20543 * paged from the remote server.
20544 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20545 * @cfg {String} root name of the property which contains the Array of row objects.
20546 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20548 * Create a new JsonReader
20549 * @param {Object} meta Metadata configuration options
20550 * @param {Object} recordType Either an Array of field definition objects,
20551 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20553 Roo.data.JsonReader = function(meta, recordType){
20556 // set some defaults:
20557 Roo.applyIf(meta, {
20558 totalProperty: 'total',
20559 successProperty : 'success',
20564 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20566 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20569 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20570 * Used by Store query builder to append _requestMeta to params.
20573 metaFromRemote : false,
20575 * This method is only used by a DataProxy which has retrieved data from a remote server.
20576 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20577 * @return {Object} data A data block which is used by an Roo.data.Store object as
20578 * a cache of Roo.data.Records.
20580 read : function(response){
20581 var json = response.responseText;
20583 var o = /* eval:var:o */ eval("("+json+")");
20585 throw {message: "JsonReader.read: Json object not found"};
20591 this.metaFromRemote = true;
20592 this.meta = o.metaData;
20593 this.recordType = Roo.data.Record.create(o.metaData.fields);
20594 this.onMetaChange(this.meta, this.recordType, o);
20596 return this.readRecords(o);
20599 // private function a store will implement
20600 onMetaChange : function(meta, recordType, o){
20607 simpleAccess: function(obj, subsc) {
20614 getJsonAccessor: function(){
20616 return function(expr) {
20618 return(re.test(expr))
20619 ? new Function("obj", "return obj." + expr)
20624 return Roo.emptyFn;
20629 * Create a data block containing Roo.data.Records from an XML document.
20630 * @param {Object} o An object which contains an Array of row objects in the property specified
20631 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20632 * which contains the total size of the dataset.
20633 * @return {Object} data A data block which is used by an Roo.data.Store object as
20634 * a cache of Roo.data.Records.
20636 readRecords : function(o){
20638 * After any data loads, the raw JSON data is available for further custom processing.
20642 var s = this.meta, Record = this.recordType,
20643 f = Record.prototype.fields, fi = f.items, fl = f.length;
20645 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20647 if(s.totalProperty) {
20648 this.getTotal = this.getJsonAccessor(s.totalProperty);
20650 if(s.successProperty) {
20651 this.getSuccess = this.getJsonAccessor(s.successProperty);
20653 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20655 var g = this.getJsonAccessor(s.id);
20656 this.getId = function(rec) {
20658 return (r === undefined || r === "") ? null : r;
20661 this.getId = function(){return null;};
20664 for(var jj = 0; jj < fl; jj++){
20666 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20667 this.ef[jj] = this.getJsonAccessor(map);
20671 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20672 if(s.totalProperty){
20673 var vt = parseInt(this.getTotal(o), 10);
20678 if(s.successProperty){
20679 var vs = this.getSuccess(o);
20680 if(vs === false || vs === 'false'){
20685 for(var i = 0; i < c; i++){
20688 var id = this.getId(n);
20689 for(var j = 0; j < fl; j++){
20691 var v = this.ef[j](n);
20693 Roo.log('missing convert for ' + f.name);
20697 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20699 var record = new Record(values, id);
20701 records[i] = record;
20706 totalRecords : totalRecords
20711 * Ext JS Library 1.1.1
20712 * Copyright(c) 2006-2007, Ext JS, LLC.
20714 * Originally Released Under LGPL - original licence link has changed is not relivant.
20717 * <script type="text/javascript">
20721 * @class Roo.data.XmlReader
20722 * @extends Roo.data.DataReader
20723 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20724 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20726 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20727 * header in the HTTP response must be set to "text/xml".</em>
20731 var RecordDef = Roo.data.Record.create([
20732 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20733 {name: 'occupation'} // This field will use "occupation" as the mapping.
20735 var myReader = new Roo.data.XmlReader({
20736 totalRecords: "results", // The element which contains the total dataset size (optional)
20737 record: "row", // The repeated element which contains row information
20738 id: "id" // The element within the row that provides an ID for the record (optional)
20742 * This would consume an XML file like this:
20746 <results>2</results>
20749 <name>Bill</name>
20750 <occupation>Gardener</occupation>
20754 <name>Ben</name>
20755 <occupation>Horticulturalist</occupation>
20759 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20760 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20761 * paged from the remote server.
20762 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20763 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20764 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20765 * a record identifier value.
20767 * Create a new XmlReader
20768 * @param {Object} meta Metadata configuration options
20769 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20770 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20771 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20773 Roo.data.XmlReader = function(meta, recordType){
20775 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20777 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20779 * This method is only used by a DataProxy which has retrieved data from a remote server.
20780 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20781 * to contain a method called 'responseXML' that returns an XML document object.
20782 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20783 * a cache of Roo.data.Records.
20785 read : function(response){
20786 var doc = response.responseXML;
20788 throw {message: "XmlReader.read: XML Document not available"};
20790 return this.readRecords(doc);
20794 * Create a data block containing Roo.data.Records from an XML document.
20795 * @param {Object} doc A parsed XML document.
20796 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20797 * a cache of Roo.data.Records.
20799 readRecords : function(doc){
20801 * After any data loads/reads, the raw XML Document is available for further custom processing.
20802 * @type XMLDocument
20804 this.xmlData = doc;
20805 var root = doc.documentElement || doc;
20806 var q = Roo.DomQuery;
20807 var recordType = this.recordType, fields = recordType.prototype.fields;
20808 var sid = this.meta.id;
20809 var totalRecords = 0, success = true;
20810 if(this.meta.totalRecords){
20811 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20814 if(this.meta.success){
20815 var sv = q.selectValue(this.meta.success, root, true);
20816 success = sv !== false && sv !== 'false';
20819 var ns = q.select(this.meta.record, root);
20820 for(var i = 0, len = ns.length; i < len; i++) {
20823 var id = sid ? q.selectValue(sid, n) : undefined;
20824 for(var j = 0, jlen = fields.length; j < jlen; j++){
20825 var f = fields.items[j];
20826 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20828 values[f.name] = v;
20830 var record = new recordType(values, id);
20832 records[records.length] = record;
20838 totalRecords : totalRecords || records.length
20843 * Ext JS Library 1.1.1
20844 * Copyright(c) 2006-2007, Ext JS, LLC.
20846 * Originally Released Under LGPL - original licence link has changed is not relivant.
20849 * <script type="text/javascript">
20853 * @class Roo.data.ArrayReader
20854 * @extends Roo.data.DataReader
20855 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20856 * Each element of that Array represents a row of data fields. The
20857 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20858 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20862 var RecordDef = Roo.data.Record.create([
20863 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20864 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20866 var myReader = new Roo.data.ArrayReader({
20867 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20871 * This would consume an Array like this:
20873 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20875 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20877 * Create a new JsonReader
20878 * @param {Object} meta Metadata configuration options.
20879 * @param {Object} recordType Either an Array of field definition objects
20880 * as specified to {@link Roo.data.Record#create},
20881 * or an {@link Roo.data.Record} object
20882 * created using {@link Roo.data.Record#create}.
20884 Roo.data.ArrayReader = function(meta, recordType){
20885 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20888 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20890 * Create a data block containing Roo.data.Records from an XML document.
20891 * @param {Object} o An Array of row objects which represents the dataset.
20892 * @return {Object} data A data block which is used by an Roo.data.Store object as
20893 * a cache of Roo.data.Records.
20895 readRecords : function(o){
20896 var sid = this.meta ? this.meta.id : null;
20897 var recordType = this.recordType, fields = recordType.prototype.fields;
20900 for(var i = 0; i < root.length; i++){
20903 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20904 for(var j = 0, jlen = fields.length; j < jlen; j++){
20905 var f = fields.items[j];
20906 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20907 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20909 values[f.name] = v;
20911 var record = new recordType(values, id);
20913 records[records.length] = record;
20917 totalRecords : records.length
20922 * Ext JS Library 1.1.1
20923 * Copyright(c) 2006-2007, Ext JS, LLC.
20925 * Originally Released Under LGPL - original licence link has changed is not relivant.
20928 * <script type="text/javascript">
20933 * @class Roo.data.Tree
20934 * @extends Roo.util.Observable
20935 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20936 * in the tree have most standard DOM functionality.
20938 * @param {Node} root (optional) The root node
20940 Roo.data.Tree = function(root){
20941 this.nodeHash = {};
20943 * The root node for this tree
20948 this.setRootNode(root);
20953 * Fires when a new child node is appended to a node in this tree.
20954 * @param {Tree} tree The owner tree
20955 * @param {Node} parent The parent node
20956 * @param {Node} node The newly appended node
20957 * @param {Number} index The index of the newly appended node
20962 * Fires when a child node is removed from a node in this tree.
20963 * @param {Tree} tree The owner tree
20964 * @param {Node} parent The parent node
20965 * @param {Node} node The child node removed
20970 * Fires when a node is moved to a new location in the tree
20971 * @param {Tree} tree The owner tree
20972 * @param {Node} node The node moved
20973 * @param {Node} oldParent The old parent of this node
20974 * @param {Node} newParent The new parent of this node
20975 * @param {Number} index The index it was moved to
20980 * Fires when a new child node is inserted in a node in this tree.
20981 * @param {Tree} tree The owner tree
20982 * @param {Node} parent The parent node
20983 * @param {Node} node The child node inserted
20984 * @param {Node} refNode The child node the node was inserted before
20988 * @event beforeappend
20989 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20990 * @param {Tree} tree The owner tree
20991 * @param {Node} parent The parent node
20992 * @param {Node} node The child node to be appended
20994 "beforeappend" : true,
20996 * @event beforeremove
20997 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20998 * @param {Tree} tree The owner tree
20999 * @param {Node} parent The parent node
21000 * @param {Node} node The child node to be removed
21002 "beforeremove" : true,
21004 * @event beforemove
21005 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21006 * @param {Tree} tree The owner tree
21007 * @param {Node} node The node being moved
21008 * @param {Node} oldParent The parent of the node
21009 * @param {Node} newParent The new parent the node is moving to
21010 * @param {Number} index The index it is being moved to
21012 "beforemove" : true,
21014 * @event beforeinsert
21015 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21016 * @param {Tree} tree The owner tree
21017 * @param {Node} parent The parent node
21018 * @param {Node} node The child node to be inserted
21019 * @param {Node} refNode The child node the node is being inserted before
21021 "beforeinsert" : true
21024 Roo.data.Tree.superclass.constructor.call(this);
21027 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21028 pathSeparator: "/",
21030 proxyNodeEvent : function(){
21031 return this.fireEvent.apply(this, arguments);
21035 * Returns the root node for this tree.
21038 getRootNode : function(){
21043 * Sets the root node for this tree.
21044 * @param {Node} node
21047 setRootNode : function(node){
21049 node.ownerTree = this;
21050 node.isRoot = true;
21051 this.registerNode(node);
21056 * Gets a node in this tree by its id.
21057 * @param {String} id
21060 getNodeById : function(id){
21061 return this.nodeHash[id];
21064 registerNode : function(node){
21065 this.nodeHash[node.id] = node;
21068 unregisterNode : function(node){
21069 delete this.nodeHash[node.id];
21072 toString : function(){
21073 return "[Tree"+(this.id?" "+this.id:"")+"]";
21078 * @class Roo.data.Node
21079 * @extends Roo.util.Observable
21080 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21081 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21083 * @param {Object} attributes The attributes/config for the node
21085 Roo.data.Node = function(attributes){
21087 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21090 this.attributes = attributes || {};
21091 this.leaf = this.attributes.leaf;
21093 * The node id. @type String
21095 this.id = this.attributes.id;
21097 this.id = Roo.id(null, "ynode-");
21098 this.attributes.id = this.id;
21101 * All child nodes of this node. @type Array
21103 this.childNodes = [];
21104 if(!this.childNodes.indexOf){ // indexOf is a must
21105 this.childNodes.indexOf = function(o){
21106 for(var i = 0, len = this.length; i < len; i++){
21115 * The parent node for this node. @type Node
21117 this.parentNode = null;
21119 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21121 this.firstChild = null;
21123 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21125 this.lastChild = null;
21127 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21129 this.previousSibling = null;
21131 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21133 this.nextSibling = null;
21138 * Fires when a new child node is appended
21139 * @param {Tree} tree The owner tree
21140 * @param {Node} this This node
21141 * @param {Node} node The newly appended node
21142 * @param {Number} index The index of the newly appended node
21147 * Fires when a child node is removed
21148 * @param {Tree} tree The owner tree
21149 * @param {Node} this This node
21150 * @param {Node} node The removed node
21155 * Fires when this node is moved to a new location in the tree
21156 * @param {Tree} tree The owner tree
21157 * @param {Node} this This node
21158 * @param {Node} oldParent The old parent of this node
21159 * @param {Node} newParent The new parent of this node
21160 * @param {Number} index The index it was moved to
21165 * Fires when a new child node is inserted.
21166 * @param {Tree} tree The owner tree
21167 * @param {Node} this This node
21168 * @param {Node} node The child node inserted
21169 * @param {Node} refNode The child node the node was inserted before
21173 * @event beforeappend
21174 * Fires before a new child is appended, return false to cancel the append.
21175 * @param {Tree} tree The owner tree
21176 * @param {Node} this This node
21177 * @param {Node} node The child node to be appended
21179 "beforeappend" : true,
21181 * @event beforeremove
21182 * Fires before a child is removed, return false to cancel the remove.
21183 * @param {Tree} tree The owner tree
21184 * @param {Node} this This node
21185 * @param {Node} node The child node to be removed
21187 "beforeremove" : true,
21189 * @event beforemove
21190 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21191 * @param {Tree} tree The owner tree
21192 * @param {Node} this This node
21193 * @param {Node} oldParent The parent of this node
21194 * @param {Node} newParent The new parent this node is moving to
21195 * @param {Number} index The index it is being moved to
21197 "beforemove" : true,
21199 * @event beforeinsert
21200 * Fires before a new child is inserted, return false to cancel the insert.
21201 * @param {Tree} tree The owner tree
21202 * @param {Node} this This node
21203 * @param {Node} node The child node to be inserted
21204 * @param {Node} refNode The child node the node is being inserted before
21206 "beforeinsert" : true
21208 this.listeners = this.attributes.listeners;
21209 Roo.data.Node.superclass.constructor.call(this);
21212 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21213 fireEvent : function(evtName){
21214 // first do standard event for this node
21215 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21218 // then bubble it up to the tree if the event wasn't cancelled
21219 var ot = this.getOwnerTree();
21221 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21229 * Returns true if this node is a leaf
21230 * @return {Boolean}
21232 isLeaf : function(){
21233 return this.leaf === true;
21237 setFirstChild : function(node){
21238 this.firstChild = node;
21242 setLastChild : function(node){
21243 this.lastChild = node;
21248 * Returns true if this node is the last child of its parent
21249 * @return {Boolean}
21251 isLast : function(){
21252 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21256 * Returns true if this node is the first child of its parent
21257 * @return {Boolean}
21259 isFirst : function(){
21260 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21263 hasChildNodes : function(){
21264 return !this.isLeaf() && this.childNodes.length > 0;
21268 * Insert node(s) as the last child node of this node.
21269 * @param {Node/Array} node The node or Array of nodes to append
21270 * @return {Node} The appended node if single append, or null if an array was passed
21272 appendChild : function(node){
21274 if(node instanceof Array){
21276 }else if(arguments.length > 1){
21279 // if passed an array or multiple args do them one by one
21281 for(var i = 0, len = multi.length; i < len; i++) {
21282 this.appendChild(multi[i]);
21285 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21288 var index = this.childNodes.length;
21289 var oldParent = node.parentNode;
21290 // it's a move, make sure we move it cleanly
21292 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21295 oldParent.removeChild(node);
21297 index = this.childNodes.length;
21299 this.setFirstChild(node);
21301 this.childNodes.push(node);
21302 node.parentNode = this;
21303 var ps = this.childNodes[index-1];
21305 node.previousSibling = ps;
21306 ps.nextSibling = node;
21308 node.previousSibling = null;
21310 node.nextSibling = null;
21311 this.setLastChild(node);
21312 node.setOwnerTree(this.getOwnerTree());
21313 this.fireEvent("append", this.ownerTree, this, node, index);
21315 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21322 * Removes a child node from this node.
21323 * @param {Node} node The node to remove
21324 * @return {Node} The removed node
21326 removeChild : function(node){
21327 var index = this.childNodes.indexOf(node);
21331 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21335 // remove it from childNodes collection
21336 this.childNodes.splice(index, 1);
21339 if(node.previousSibling){
21340 node.previousSibling.nextSibling = node.nextSibling;
21342 if(node.nextSibling){
21343 node.nextSibling.previousSibling = node.previousSibling;
21346 // update child refs
21347 if(this.firstChild == node){
21348 this.setFirstChild(node.nextSibling);
21350 if(this.lastChild == node){
21351 this.setLastChild(node.previousSibling);
21354 node.setOwnerTree(null);
21355 // clear any references from the node
21356 node.parentNode = null;
21357 node.previousSibling = null;
21358 node.nextSibling = null;
21359 this.fireEvent("remove", this.ownerTree, this, node);
21364 * Inserts the first node before the second node in this nodes childNodes collection.
21365 * @param {Node} node The node to insert
21366 * @param {Node} refNode The node to insert before (if null the node is appended)
21367 * @return {Node} The inserted node
21369 insertBefore : function(node, refNode){
21370 if(!refNode){ // like standard Dom, refNode can be null for append
21371 return this.appendChild(node);
21374 if(node == refNode){
21378 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21381 var index = this.childNodes.indexOf(refNode);
21382 var oldParent = node.parentNode;
21383 var refIndex = index;
21385 // when moving internally, indexes will change after remove
21386 if(oldParent == this && this.childNodes.indexOf(node) < index){
21390 // it's a move, make sure we move it cleanly
21392 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21395 oldParent.removeChild(node);
21398 this.setFirstChild(node);
21400 this.childNodes.splice(refIndex, 0, node);
21401 node.parentNode = this;
21402 var ps = this.childNodes[refIndex-1];
21404 node.previousSibling = ps;
21405 ps.nextSibling = node;
21407 node.previousSibling = null;
21409 node.nextSibling = refNode;
21410 refNode.previousSibling = node;
21411 node.setOwnerTree(this.getOwnerTree());
21412 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21414 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21420 * Returns the child node at the specified index.
21421 * @param {Number} index
21424 item : function(index){
21425 return this.childNodes[index];
21429 * Replaces one child node in this node with another.
21430 * @param {Node} newChild The replacement node
21431 * @param {Node} oldChild The node to replace
21432 * @return {Node} The replaced node
21434 replaceChild : function(newChild, oldChild){
21435 this.insertBefore(newChild, oldChild);
21436 this.removeChild(oldChild);
21441 * Returns the index of a child node
21442 * @param {Node} node
21443 * @return {Number} The index of the node or -1 if it was not found
21445 indexOf : function(child){
21446 return this.childNodes.indexOf(child);
21450 * Returns the tree this node is in.
21453 getOwnerTree : function(){
21454 // if it doesn't have one, look for one
21455 if(!this.ownerTree){
21459 this.ownerTree = p.ownerTree;
21465 return this.ownerTree;
21469 * Returns depth of this node (the root node has a depth of 0)
21472 getDepth : function(){
21475 while(p.parentNode){
21483 setOwnerTree : function(tree){
21484 // if it's move, we need to update everyone
21485 if(tree != this.ownerTree){
21486 if(this.ownerTree){
21487 this.ownerTree.unregisterNode(this);
21489 this.ownerTree = tree;
21490 var cs = this.childNodes;
21491 for(var i = 0, len = cs.length; i < len; i++) {
21492 cs[i].setOwnerTree(tree);
21495 tree.registerNode(this);
21501 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21502 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21503 * @return {String} The path
21505 getPath : function(attr){
21506 attr = attr || "id";
21507 var p = this.parentNode;
21508 var b = [this.attributes[attr]];
21510 b.unshift(p.attributes[attr]);
21513 var sep = this.getOwnerTree().pathSeparator;
21514 return sep + b.join(sep);
21518 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21519 * function call will be the scope provided or the current node. The arguments to the function
21520 * will be the args provided or the current node. If the function returns false at any point,
21521 * the bubble is stopped.
21522 * @param {Function} fn The function to call
21523 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21524 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21526 bubble : function(fn, scope, args){
21529 if(fn.call(scope || p, args || p) === false){
21537 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21538 * function call will be the scope provided or the current node. The arguments to the function
21539 * will be the args provided or the current node. If the function returns false at any point,
21540 * the cascade is stopped on that branch.
21541 * @param {Function} fn The function to call
21542 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21543 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21545 cascade : function(fn, scope, args){
21546 if(fn.call(scope || this, args || this) !== false){
21547 var cs = this.childNodes;
21548 for(var i = 0, len = cs.length; i < len; i++) {
21549 cs[i].cascade(fn, scope, args);
21555 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21556 * function call will be the scope provided or the current node. The arguments to the function
21557 * will be the args provided or the current node. If the function returns false at any point,
21558 * the iteration stops.
21559 * @param {Function} fn The function to call
21560 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21561 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21563 eachChild : function(fn, scope, args){
21564 var cs = this.childNodes;
21565 for(var i = 0, len = cs.length; i < len; i++) {
21566 if(fn.call(scope || this, args || cs[i]) === false){
21573 * Finds the first child that has the attribute with the specified value.
21574 * @param {String} attribute The attribute name
21575 * @param {Mixed} value The value to search for
21576 * @return {Node} The found child or null if none was found
21578 findChild : function(attribute, value){
21579 var cs = this.childNodes;
21580 for(var i = 0, len = cs.length; i < len; i++) {
21581 if(cs[i].attributes[attribute] == value){
21589 * Finds the first child by a custom function. The child matches if the function passed
21591 * @param {Function} fn
21592 * @param {Object} scope (optional)
21593 * @return {Node} The found child or null if none was found
21595 findChildBy : function(fn, scope){
21596 var cs = this.childNodes;
21597 for(var i = 0, len = cs.length; i < len; i++) {
21598 if(fn.call(scope||cs[i], cs[i]) === true){
21606 * Sorts this nodes children using the supplied sort function
21607 * @param {Function} fn
21608 * @param {Object} scope (optional)
21610 sort : function(fn, scope){
21611 var cs = this.childNodes;
21612 var len = cs.length;
21614 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21616 for(var i = 0; i < len; i++){
21618 n.previousSibling = cs[i-1];
21619 n.nextSibling = cs[i+1];
21621 this.setFirstChild(n);
21624 this.setLastChild(n);
21631 * Returns true if this node is an ancestor (at any point) of the passed node.
21632 * @param {Node} node
21633 * @return {Boolean}
21635 contains : function(node){
21636 return node.isAncestor(this);
21640 * Returns true if the passed node is an ancestor (at any point) of this node.
21641 * @param {Node} node
21642 * @return {Boolean}
21644 isAncestor : function(node){
21645 var p = this.parentNode;
21655 toString : function(){
21656 return "[Node"+(this.id?" "+this.id:"")+"]";
21660 * Ext JS Library 1.1.1
21661 * Copyright(c) 2006-2007, Ext JS, LLC.
21663 * Originally Released Under LGPL - original licence link has changed is not relivant.
21666 * <script type="text/javascript">
21671 * @class Roo.ComponentMgr
21672 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21675 Roo.ComponentMgr = function(){
21676 var all = new Roo.util.MixedCollection();
21680 * Registers a component.
21681 * @param {Roo.Component} c The component
21683 register : function(c){
21688 * Unregisters a component.
21689 * @param {Roo.Component} c The component
21691 unregister : function(c){
21696 * Returns a component by id
21697 * @param {String} id The component id
21699 get : function(id){
21700 return all.get(id);
21704 * Registers a function that will be called when a specified component is added to ComponentMgr
21705 * @param {String} id The component id
21706 * @param {Funtction} fn The callback function
21707 * @param {Object} scope The scope of the callback
21709 onAvailable : function(id, fn, scope){
21710 all.on("add", function(index, o){
21712 fn.call(scope || o, o);
21713 all.un("add", fn, scope);
21720 * Ext JS Library 1.1.1
21721 * Copyright(c) 2006-2007, Ext JS, LLC.
21723 * Originally Released Under LGPL - original licence link has changed is not relivant.
21726 * <script type="text/javascript">
21730 * @class Roo.Component
21731 * @extends Roo.util.Observable
21732 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21733 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21734 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21735 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21736 * All visual components (widgets) that require rendering into a layout should subclass Component.
21738 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21739 * 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
21740 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21742 Roo.Component = function(config){
21743 config = config || {};
21744 if(config.tagName || config.dom || typeof config == "string"){ // element object
21745 config = {el: config, id: config.id || config};
21747 this.initialConfig = config;
21749 Roo.apply(this, config);
21753 * Fires after the component is disabled.
21754 * @param {Roo.Component} this
21759 * Fires after the component is enabled.
21760 * @param {Roo.Component} this
21764 * @event beforeshow
21765 * Fires before the component is shown. Return false to stop the show.
21766 * @param {Roo.Component} this
21771 * Fires after the component is shown.
21772 * @param {Roo.Component} this
21776 * @event beforehide
21777 * Fires before the component is hidden. Return false to stop the hide.
21778 * @param {Roo.Component} this
21783 * Fires after the component is hidden.
21784 * @param {Roo.Component} this
21788 * @event beforerender
21789 * Fires before the component is rendered. Return false to stop the render.
21790 * @param {Roo.Component} this
21792 beforerender : true,
21795 * Fires after the component is rendered.
21796 * @param {Roo.Component} this
21800 * @event beforedestroy
21801 * Fires before the component is destroyed. Return false to stop the destroy.
21802 * @param {Roo.Component} this
21804 beforedestroy : true,
21807 * Fires after the component is destroyed.
21808 * @param {Roo.Component} this
21813 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21815 Roo.ComponentMgr.register(this);
21816 Roo.Component.superclass.constructor.call(this);
21817 this.initComponent();
21818 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21819 this.render(this.renderTo);
21820 delete this.renderTo;
21825 Roo.Component.AUTO_ID = 1000;
21827 Roo.extend(Roo.Component, Roo.util.Observable, {
21829 * @property {Boolean} hidden
21830 * true if this component is hidden. Read-only.
21834 * true if this component is disabled. Read-only.
21838 * true if this component has been rendered. Read-only.
21842 /** @cfg {String} disableClass
21843 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21845 disabledClass : "x-item-disabled",
21846 /** @cfg {Boolean} allowDomMove
21847 * Whether the component can move the Dom node when rendering (defaults to true).
21849 allowDomMove : true,
21850 /** @cfg {String} hideMode
21851 * How this component should hidden. Supported values are
21852 * "visibility" (css visibility), "offsets" (negative offset position) and
21853 * "display" (css display) - defaults to "display".
21855 hideMode: 'display',
21858 ctype : "Roo.Component",
21860 /** @cfg {String} actionMode
21861 * which property holds the element that used for hide() / show() / disable() / enable()
21867 getActionEl : function(){
21868 return this[this.actionMode];
21871 initComponent : Roo.emptyFn,
21873 * If this is a lazy rendering component, render it to its container element.
21874 * @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.
21876 render : function(container, position){
21877 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21878 if(!container && this.el){
21879 this.el = Roo.get(this.el);
21880 container = this.el.dom.parentNode;
21881 this.allowDomMove = false;
21883 this.container = Roo.get(container);
21884 this.rendered = true;
21885 if(position !== undefined){
21886 if(typeof position == 'number'){
21887 position = this.container.dom.childNodes[position];
21889 position = Roo.getDom(position);
21892 this.onRender(this.container, position || null);
21894 this.el.addClass(this.cls);
21898 this.el.applyStyles(this.style);
21901 this.fireEvent("render", this);
21902 this.afterRender(this.container);
21914 // default function is not really useful
21915 onRender : function(ct, position){
21917 this.el = Roo.get(this.el);
21918 if(this.allowDomMove !== false){
21919 ct.dom.insertBefore(this.el.dom, position);
21925 getAutoCreate : function(){
21926 var cfg = typeof this.autoCreate == "object" ?
21927 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21928 if(this.id && !cfg.id){
21935 afterRender : Roo.emptyFn,
21938 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21939 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21941 destroy : function(){
21942 if(this.fireEvent("beforedestroy", this) !== false){
21943 this.purgeListeners();
21944 this.beforeDestroy();
21946 this.el.removeAllListeners();
21948 if(this.actionMode == "container"){
21949 this.container.remove();
21953 Roo.ComponentMgr.unregister(this);
21954 this.fireEvent("destroy", this);
21959 beforeDestroy : function(){
21964 onDestroy : function(){
21969 * Returns the underlying {@link Roo.Element}.
21970 * @return {Roo.Element} The element
21972 getEl : function(){
21977 * Returns the id of this component.
21980 getId : function(){
21985 * Try to focus this component.
21986 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21987 * @return {Roo.Component} this
21989 focus : function(selectText){
21992 if(selectText === true){
21993 this.el.dom.select();
22008 * Disable this component.
22009 * @return {Roo.Component} this
22011 disable : function(){
22015 this.disabled = true;
22016 this.fireEvent("disable", this);
22021 onDisable : function(){
22022 this.getActionEl().addClass(this.disabledClass);
22023 this.el.dom.disabled = true;
22027 * Enable this component.
22028 * @return {Roo.Component} this
22030 enable : function(){
22034 this.disabled = false;
22035 this.fireEvent("enable", this);
22040 onEnable : function(){
22041 this.getActionEl().removeClass(this.disabledClass);
22042 this.el.dom.disabled = false;
22046 * Convenience function for setting disabled/enabled by boolean.
22047 * @param {Boolean} disabled
22049 setDisabled : function(disabled){
22050 this[disabled ? "disable" : "enable"]();
22054 * Show this component.
22055 * @return {Roo.Component} this
22058 if(this.fireEvent("beforeshow", this) !== false){
22059 this.hidden = false;
22063 this.fireEvent("show", this);
22069 onShow : function(){
22070 var ae = this.getActionEl();
22071 if(this.hideMode == 'visibility'){
22072 ae.dom.style.visibility = "visible";
22073 }else if(this.hideMode == 'offsets'){
22074 ae.removeClass('x-hidden');
22076 ae.dom.style.display = "";
22081 * Hide this component.
22082 * @return {Roo.Component} this
22085 if(this.fireEvent("beforehide", this) !== false){
22086 this.hidden = true;
22090 this.fireEvent("hide", this);
22096 onHide : function(){
22097 var ae = this.getActionEl();
22098 if(this.hideMode == 'visibility'){
22099 ae.dom.style.visibility = "hidden";
22100 }else if(this.hideMode == 'offsets'){
22101 ae.addClass('x-hidden');
22103 ae.dom.style.display = "none";
22108 * Convenience function to hide or show this component by boolean.
22109 * @param {Boolean} visible True to show, false to hide
22110 * @return {Roo.Component} this
22112 setVisible: function(visible){
22122 * Returns true if this component is visible.
22124 isVisible : function(){
22125 return this.getActionEl().isVisible();
22128 cloneConfig : function(overrides){
22129 overrides = overrides || {};
22130 var id = overrides.id || Roo.id();
22131 var cfg = Roo.applyIf(overrides, this.initialConfig);
22132 cfg.id = id; // prevent dup id
22133 return new this.constructor(cfg);
22137 * Ext JS Library 1.1.1
22138 * Copyright(c) 2006-2007, Ext JS, LLC.
22140 * Originally Released Under LGPL - original licence link has changed is not relivant.
22143 * <script type="text/javascript">
22148 * @extends Roo.Element
22149 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22150 * automatic maintaining of shadow/shim positions.
22151 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22152 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22153 * you can pass a string with a CSS class name. False turns off the shadow.
22154 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22155 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22156 * @cfg {String} cls CSS class to add to the element
22157 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22158 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22160 * @param {Object} config An object with config options.
22161 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22164 Roo.Layer = function(config, existingEl){
22165 config = config || {};
22166 var dh = Roo.DomHelper;
22167 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22169 this.dom = Roo.getDom(existingEl);
22172 var o = config.dh || {tag: "div", cls: "x-layer"};
22173 this.dom = dh.append(pel, o);
22176 this.addClass(config.cls);
22178 this.constrain = config.constrain !== false;
22179 this.visibilityMode = Roo.Element.VISIBILITY;
22181 this.id = this.dom.id = config.id;
22183 this.id = Roo.id(this.dom);
22185 this.zindex = config.zindex || this.getZIndex();
22186 this.position("absolute", this.zindex);
22188 this.shadowOffset = config.shadowOffset || 4;
22189 this.shadow = new Roo.Shadow({
22190 offset : this.shadowOffset,
22191 mode : config.shadow
22194 this.shadowOffset = 0;
22196 this.useShim = config.shim !== false && Roo.useShims;
22197 this.useDisplay = config.useDisplay;
22201 var supr = Roo.Element.prototype;
22203 // shims are shared among layer to keep from having 100 iframes
22206 Roo.extend(Roo.Layer, Roo.Element, {
22208 getZIndex : function(){
22209 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22212 getShim : function(){
22219 var shim = shims.shift();
22221 shim = this.createShim();
22222 shim.enableDisplayMode('block');
22223 shim.dom.style.display = 'none';
22224 shim.dom.style.visibility = 'visible';
22226 var pn = this.dom.parentNode;
22227 if(shim.dom.parentNode != pn){
22228 pn.insertBefore(shim.dom, this.dom);
22230 shim.setStyle('z-index', this.getZIndex()-2);
22235 hideShim : function(){
22237 this.shim.setDisplayed(false);
22238 shims.push(this.shim);
22243 disableShadow : function(){
22245 this.shadowDisabled = true;
22246 this.shadow.hide();
22247 this.lastShadowOffset = this.shadowOffset;
22248 this.shadowOffset = 0;
22252 enableShadow : function(show){
22254 this.shadowDisabled = false;
22255 this.shadowOffset = this.lastShadowOffset;
22256 delete this.lastShadowOffset;
22264 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22265 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22266 sync : function(doShow){
22267 var sw = this.shadow;
22268 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22269 var sh = this.getShim();
22271 var w = this.getWidth(),
22272 h = this.getHeight();
22274 var l = this.getLeft(true),
22275 t = this.getTop(true);
22277 if(sw && !this.shadowDisabled){
22278 if(doShow && !sw.isVisible()){
22281 sw.realign(l, t, w, h);
22287 // fit the shim behind the shadow, so it is shimmed too
22288 var a = sw.adjusts, s = sh.dom.style;
22289 s.left = (Math.min(l, l+a.l))+"px";
22290 s.top = (Math.min(t, t+a.t))+"px";
22291 s.width = (w+a.w)+"px";
22292 s.height = (h+a.h)+"px";
22299 sh.setLeftTop(l, t);
22306 destroy : function(){
22309 this.shadow.hide();
22311 this.removeAllListeners();
22312 var pn = this.dom.parentNode;
22314 pn.removeChild(this.dom);
22316 Roo.Element.uncache(this.id);
22319 remove : function(){
22324 beginUpdate : function(){
22325 this.updating = true;
22329 endUpdate : function(){
22330 this.updating = false;
22335 hideUnders : function(negOffset){
22337 this.shadow.hide();
22343 constrainXY : function(){
22344 if(this.constrain){
22345 var vw = Roo.lib.Dom.getViewWidth(),
22346 vh = Roo.lib.Dom.getViewHeight();
22347 var s = Roo.get(document).getScroll();
22349 var xy = this.getXY();
22350 var x = xy[0], y = xy[1];
22351 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22352 // only move it if it needs it
22354 // first validate right/bottom
22355 if((x + w) > vw+s.left){
22356 x = vw - w - this.shadowOffset;
22359 if((y + h) > vh+s.top){
22360 y = vh - h - this.shadowOffset;
22363 // then make sure top/left isn't negative
22374 var ay = this.avoidY;
22375 if(y <= ay && (y+h) >= ay){
22381 supr.setXY.call(this, xy);
22387 isVisible : function(){
22388 return this.visible;
22392 showAction : function(){
22393 this.visible = true; // track visibility to prevent getStyle calls
22394 if(this.useDisplay === true){
22395 this.setDisplayed("");
22396 }else if(this.lastXY){
22397 supr.setXY.call(this, this.lastXY);
22398 }else if(this.lastLT){
22399 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22404 hideAction : function(){
22405 this.visible = false;
22406 if(this.useDisplay === true){
22407 this.setDisplayed(false);
22409 this.setLeftTop(-10000,-10000);
22413 // overridden Element method
22414 setVisible : function(v, a, d, c, e){
22419 var cb = function(){
22424 }.createDelegate(this);
22425 supr.setVisible.call(this, true, true, d, cb, e);
22428 this.hideUnders(true);
22437 }.createDelegate(this);
22439 supr.setVisible.call(this, v, a, d, cb, e);
22448 storeXY : function(xy){
22449 delete this.lastLT;
22453 storeLeftTop : function(left, top){
22454 delete this.lastXY;
22455 this.lastLT = [left, top];
22459 beforeFx : function(){
22460 this.beforeAction();
22461 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22465 afterFx : function(){
22466 Roo.Layer.superclass.afterFx.apply(this, arguments);
22467 this.sync(this.isVisible());
22471 beforeAction : function(){
22472 if(!this.updating && this.shadow){
22473 this.shadow.hide();
22477 // overridden Element method
22478 setLeft : function(left){
22479 this.storeLeftTop(left, this.getTop(true));
22480 supr.setLeft.apply(this, arguments);
22484 setTop : function(top){
22485 this.storeLeftTop(this.getLeft(true), top);
22486 supr.setTop.apply(this, arguments);
22490 setLeftTop : function(left, top){
22491 this.storeLeftTop(left, top);
22492 supr.setLeftTop.apply(this, arguments);
22496 setXY : function(xy, a, d, c, e){
22498 this.beforeAction();
22500 var cb = this.createCB(c);
22501 supr.setXY.call(this, xy, a, d, cb, e);
22508 createCB : function(c){
22519 // overridden Element method
22520 setX : function(x, a, d, c, e){
22521 this.setXY([x, this.getY()], a, d, c, e);
22524 // overridden Element method
22525 setY : function(y, a, d, c, e){
22526 this.setXY([this.getX(), y], a, d, c, e);
22529 // overridden Element method
22530 setSize : function(w, h, a, d, c, e){
22531 this.beforeAction();
22532 var cb = this.createCB(c);
22533 supr.setSize.call(this, w, h, a, d, cb, e);
22539 // overridden Element method
22540 setWidth : function(w, a, d, c, e){
22541 this.beforeAction();
22542 var cb = this.createCB(c);
22543 supr.setWidth.call(this, w, a, d, cb, e);
22549 // overridden Element method
22550 setHeight : function(h, a, d, c, e){
22551 this.beforeAction();
22552 var cb = this.createCB(c);
22553 supr.setHeight.call(this, h, a, d, cb, e);
22559 // overridden Element method
22560 setBounds : function(x, y, w, h, a, d, c, e){
22561 this.beforeAction();
22562 var cb = this.createCB(c);
22564 this.storeXY([x, y]);
22565 supr.setXY.call(this, [x, y]);
22566 supr.setSize.call(this, w, h, a, d, cb, e);
22569 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22575 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22576 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22577 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22578 * @param {Number} zindex The new z-index to set
22579 * @return {this} The Layer
22581 setZIndex : function(zindex){
22582 this.zindex = zindex;
22583 this.setStyle("z-index", zindex + 2);
22585 this.shadow.setZIndex(zindex + 1);
22588 this.shim.setStyle("z-index", zindex);
22594 * Ext JS Library 1.1.1
22595 * Copyright(c) 2006-2007, Ext JS, LLC.
22597 * Originally Released Under LGPL - original licence link has changed is not relivant.
22600 * <script type="text/javascript">
22605 * @class Roo.Shadow
22606 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22607 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22608 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22610 * Create a new Shadow
22611 * @param {Object} config The config object
22613 Roo.Shadow = function(config){
22614 Roo.apply(this, config);
22615 if(typeof this.mode != "string"){
22616 this.mode = this.defaultMode;
22618 var o = this.offset, a = {h: 0};
22619 var rad = Math.floor(this.offset/2);
22620 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22626 a.l -= this.offset + rad;
22627 a.t -= this.offset + rad;
22638 a.l -= (this.offset - rad);
22639 a.t -= this.offset + rad;
22641 a.w -= (this.offset - rad)*2;
22652 a.l -= (this.offset - rad);
22653 a.t -= (this.offset - rad);
22655 a.w -= (this.offset + rad + 1);
22656 a.h -= (this.offset + rad);
22665 Roo.Shadow.prototype = {
22667 * @cfg {String} mode
22668 * The shadow display mode. Supports the following options:<br />
22669 * sides: Shadow displays on both sides and bottom only<br />
22670 * frame: Shadow displays equally on all four sides<br />
22671 * drop: Traditional bottom-right drop shadow (default)
22674 * @cfg {String} offset
22675 * The number of pixels to offset the shadow from the element (defaults to 4)
22680 defaultMode: "drop",
22683 * Displays the shadow under the target element
22684 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22686 show : function(target){
22687 target = Roo.get(target);
22689 this.el = Roo.Shadow.Pool.pull();
22690 if(this.el.dom.nextSibling != target.dom){
22691 this.el.insertBefore(target);
22694 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22696 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22699 target.getLeft(true),
22700 target.getTop(true),
22704 this.el.dom.style.display = "block";
22708 * Returns true if the shadow is visible, else false
22710 isVisible : function(){
22711 return this.el ? true : false;
22715 * Direct alignment when values are already available. Show must be called at least once before
22716 * calling this method to ensure it is initialized.
22717 * @param {Number} left The target element left position
22718 * @param {Number} top The target element top position
22719 * @param {Number} width The target element width
22720 * @param {Number} height The target element height
22722 realign : function(l, t, w, h){
22726 var a = this.adjusts, d = this.el.dom, s = d.style;
22728 s.left = (l+a.l)+"px";
22729 s.top = (t+a.t)+"px";
22730 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22732 if(s.width != sws || s.height != shs){
22736 var cn = d.childNodes;
22737 var sww = Math.max(0, (sw-12))+"px";
22738 cn[0].childNodes[1].style.width = sww;
22739 cn[1].childNodes[1].style.width = sww;
22740 cn[2].childNodes[1].style.width = sww;
22741 cn[1].style.height = Math.max(0, (sh-12))+"px";
22747 * Hides this shadow
22751 this.el.dom.style.display = "none";
22752 Roo.Shadow.Pool.push(this.el);
22758 * Adjust the z-index of this shadow
22759 * @param {Number} zindex The new z-index
22761 setZIndex : function(z){
22764 this.el.setStyle("z-index", z);
22769 // Private utility class that manages the internal Shadow cache
22770 Roo.Shadow.Pool = function(){
22772 var markup = Roo.isIE ?
22773 '<div class="x-ie-shadow"></div>' :
22774 '<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>';
22777 var sh = p.shift();
22779 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22780 sh.autoBoxAdjust = false;
22785 push : function(sh){
22791 * Ext JS Library 1.1.1
22792 * Copyright(c) 2006-2007, Ext JS, LLC.
22794 * Originally Released Under LGPL - original licence link has changed is not relivant.
22797 * <script type="text/javascript">
22801 * @class Roo.BoxComponent
22802 * @extends Roo.Component
22803 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22804 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22805 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22806 * layout containers.
22808 * @param {Roo.Element/String/Object} config The configuration options.
22810 Roo.BoxComponent = function(config){
22811 Roo.Component.call(this, config);
22815 * Fires after the component is resized.
22816 * @param {Roo.Component} this
22817 * @param {Number} adjWidth The box-adjusted width that was set
22818 * @param {Number} adjHeight The box-adjusted height that was set
22819 * @param {Number} rawWidth The width that was originally specified
22820 * @param {Number} rawHeight The height that was originally specified
22825 * Fires after the component is moved.
22826 * @param {Roo.Component} this
22827 * @param {Number} x The new x position
22828 * @param {Number} y The new y position
22834 Roo.extend(Roo.BoxComponent, Roo.Component, {
22835 // private, set in afterRender to signify that the component has been rendered
22837 // private, used to defer height settings to subclasses
22838 deferHeight: false,
22839 /** @cfg {Number} width
22840 * width (optional) size of component
22842 /** @cfg {Number} height
22843 * height (optional) size of component
22847 * Sets the width and height of the component. This method fires the resize event. This method can accept
22848 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22849 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22850 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22851 * @return {Roo.BoxComponent} this
22853 setSize : function(w, h){
22854 // support for standard size objects
22855 if(typeof w == 'object'){
22860 if(!this.boxReady){
22866 // prevent recalcs when not needed
22867 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22870 this.lastSize = {width: w, height: h};
22872 var adj = this.adjustSize(w, h);
22873 var aw = adj.width, ah = adj.height;
22874 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22875 var rz = this.getResizeEl();
22876 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22877 rz.setSize(aw, ah);
22878 }else if(!this.deferHeight && ah !== undefined){
22880 }else if(aw !== undefined){
22883 this.onResize(aw, ah, w, h);
22884 this.fireEvent('resize', this, aw, ah, w, h);
22890 * Gets the current size of the component's underlying element.
22891 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22893 getSize : function(){
22894 return this.el.getSize();
22898 * Gets the current XY position of the component's underlying element.
22899 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22900 * @return {Array} The XY position of the element (e.g., [100, 200])
22902 getPosition : function(local){
22903 if(local === true){
22904 return [this.el.getLeft(true), this.el.getTop(true)];
22906 return this.xy || this.el.getXY();
22910 * Gets the current box measurements of the component's underlying element.
22911 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22912 * @returns {Object} box An object in the format {x, y, width, height}
22914 getBox : function(local){
22915 var s = this.el.getSize();
22917 s.x = this.el.getLeft(true);
22918 s.y = this.el.getTop(true);
22920 var xy = this.xy || this.el.getXY();
22928 * Sets the current box measurements of the component's underlying element.
22929 * @param {Object} box An object in the format {x, y, width, height}
22930 * @returns {Roo.BoxComponent} this
22932 updateBox : function(box){
22933 this.setSize(box.width, box.height);
22934 this.setPagePosition(box.x, box.y);
22939 getResizeEl : function(){
22940 return this.resizeEl || this.el;
22944 getPositionEl : function(){
22945 return this.positionEl || this.el;
22949 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22950 * This method fires the move event.
22951 * @param {Number} left The new left
22952 * @param {Number} top The new top
22953 * @returns {Roo.BoxComponent} this
22955 setPosition : function(x, y){
22958 if(!this.boxReady){
22961 var adj = this.adjustPosition(x, y);
22962 var ax = adj.x, ay = adj.y;
22964 var el = this.getPositionEl();
22965 if(ax !== undefined || ay !== undefined){
22966 if(ax !== undefined && ay !== undefined){
22967 el.setLeftTop(ax, ay);
22968 }else if(ax !== undefined){
22970 }else if(ay !== undefined){
22973 this.onPosition(ax, ay);
22974 this.fireEvent('move', this, ax, ay);
22980 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22981 * This method fires the move event.
22982 * @param {Number} x The new x position
22983 * @param {Number} y The new y position
22984 * @returns {Roo.BoxComponent} this
22986 setPagePosition : function(x, y){
22989 if(!this.boxReady){
22992 if(x === undefined || y === undefined){ // cannot translate undefined points
22995 var p = this.el.translatePoints(x, y);
22996 this.setPosition(p.left, p.top);
23001 onRender : function(ct, position){
23002 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23004 this.resizeEl = Roo.get(this.resizeEl);
23006 if(this.positionEl){
23007 this.positionEl = Roo.get(this.positionEl);
23012 afterRender : function(){
23013 Roo.BoxComponent.superclass.afterRender.call(this);
23014 this.boxReady = true;
23015 this.setSize(this.width, this.height);
23016 if(this.x || this.y){
23017 this.setPosition(this.x, this.y);
23019 if(this.pageX || this.pageY){
23020 this.setPagePosition(this.pageX, this.pageY);
23025 * Force the component's size to recalculate based on the underlying element's current height and width.
23026 * @returns {Roo.BoxComponent} this
23028 syncSize : function(){
23029 delete this.lastSize;
23030 this.setSize(this.el.getWidth(), this.el.getHeight());
23035 * Called after the component is resized, this method is empty by default but can be implemented by any
23036 * subclass that needs to perform custom logic after a resize occurs.
23037 * @param {Number} adjWidth The box-adjusted width that was set
23038 * @param {Number} adjHeight The box-adjusted height that was set
23039 * @param {Number} rawWidth The width that was originally specified
23040 * @param {Number} rawHeight The height that was originally specified
23042 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23047 * Called after the component is moved, this method is empty by default but can be implemented by any
23048 * subclass that needs to perform custom logic after a move occurs.
23049 * @param {Number} x The new x position
23050 * @param {Number} y The new y position
23052 onPosition : function(x, y){
23057 adjustSize : function(w, h){
23058 if(this.autoWidth){
23061 if(this.autoHeight){
23064 return {width : w, height: h};
23068 adjustPosition : function(x, y){
23069 return {x : x, y: y};
23073 * Ext JS Library 1.1.1
23074 * Copyright(c) 2006-2007, Ext JS, LLC.
23076 * Originally Released Under LGPL - original licence link has changed is not relivant.
23079 * <script type="text/javascript">
23084 * @class Roo.SplitBar
23085 * @extends Roo.util.Observable
23086 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23090 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23091 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23092 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23093 split.minSize = 100;
23094 split.maxSize = 600;
23095 split.animate = true;
23096 split.on('moved', splitterMoved);
23099 * Create a new SplitBar
23100 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23101 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23102 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23103 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23104 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23105 position of the SplitBar).
23107 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23110 this.el = Roo.get(dragElement, true);
23111 this.el.dom.unselectable = "on";
23113 this.resizingEl = Roo.get(resizingElement, true);
23117 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23118 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23121 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23124 * The minimum size of the resizing element. (Defaults to 0)
23130 * The maximum size of the resizing element. (Defaults to 2000)
23133 this.maxSize = 2000;
23136 * Whether to animate the transition to the new size
23139 this.animate = false;
23142 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23145 this.useShim = false;
23150 if(!existingProxy){
23152 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23154 this.proxy = Roo.get(existingProxy).dom;
23157 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23160 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23163 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23166 this.dragSpecs = {};
23169 * @private The adapter to use to positon and resize elements
23171 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23172 this.adapter.init(this);
23174 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23176 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23177 this.el.addClass("x-splitbar-h");
23180 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23181 this.el.addClass("x-splitbar-v");
23187 * Fires when the splitter is moved (alias for {@link #event-moved})
23188 * @param {Roo.SplitBar} this
23189 * @param {Number} newSize the new width or height
23194 * Fires when the splitter is moved
23195 * @param {Roo.SplitBar} this
23196 * @param {Number} newSize the new width or height
23200 * @event beforeresize
23201 * Fires before the splitter is dragged
23202 * @param {Roo.SplitBar} this
23204 "beforeresize" : true,
23206 "beforeapply" : true
23209 Roo.util.Observable.call(this);
23212 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23213 onStartProxyDrag : function(x, y){
23214 this.fireEvent("beforeresize", this);
23216 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23218 o.enableDisplayMode("block");
23219 // all splitbars share the same overlay
23220 Roo.SplitBar.prototype.overlay = o;
23222 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23223 this.overlay.show();
23224 Roo.get(this.proxy).setDisplayed("block");
23225 var size = this.adapter.getElementSize(this);
23226 this.activeMinSize = this.getMinimumSize();;
23227 this.activeMaxSize = this.getMaximumSize();;
23228 var c1 = size - this.activeMinSize;
23229 var c2 = Math.max(this.activeMaxSize - size, 0);
23230 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23231 this.dd.resetConstraints();
23232 this.dd.setXConstraint(
23233 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23234 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23236 this.dd.setYConstraint(0, 0);
23238 this.dd.resetConstraints();
23239 this.dd.setXConstraint(0, 0);
23240 this.dd.setYConstraint(
23241 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23242 this.placement == Roo.SplitBar.TOP ? c2 : c1
23245 this.dragSpecs.startSize = size;
23246 this.dragSpecs.startPoint = [x, y];
23247 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23251 * @private Called after the drag operation by the DDProxy
23253 onEndProxyDrag : function(e){
23254 Roo.get(this.proxy).setDisplayed(false);
23255 var endPoint = Roo.lib.Event.getXY(e);
23257 this.overlay.hide();
23260 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23261 newSize = this.dragSpecs.startSize +
23262 (this.placement == Roo.SplitBar.LEFT ?
23263 endPoint[0] - this.dragSpecs.startPoint[0] :
23264 this.dragSpecs.startPoint[0] - endPoint[0]
23267 newSize = this.dragSpecs.startSize +
23268 (this.placement == Roo.SplitBar.TOP ?
23269 endPoint[1] - this.dragSpecs.startPoint[1] :
23270 this.dragSpecs.startPoint[1] - endPoint[1]
23273 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23274 if(newSize != this.dragSpecs.startSize){
23275 if(this.fireEvent('beforeapply', this, newSize) !== false){
23276 this.adapter.setElementSize(this, newSize);
23277 this.fireEvent("moved", this, newSize);
23278 this.fireEvent("resize", this, newSize);
23284 * Get the adapter this SplitBar uses
23285 * @return The adapter object
23287 getAdapter : function(){
23288 return this.adapter;
23292 * Set the adapter this SplitBar uses
23293 * @param {Object} adapter A SplitBar adapter object
23295 setAdapter : function(adapter){
23296 this.adapter = adapter;
23297 this.adapter.init(this);
23301 * Gets the minimum size for the resizing element
23302 * @return {Number} The minimum size
23304 getMinimumSize : function(){
23305 return this.minSize;
23309 * Sets the minimum size for the resizing element
23310 * @param {Number} minSize The minimum size
23312 setMinimumSize : function(minSize){
23313 this.minSize = minSize;
23317 * Gets the maximum size for the resizing element
23318 * @return {Number} The maximum size
23320 getMaximumSize : function(){
23321 return this.maxSize;
23325 * Sets the maximum size for the resizing element
23326 * @param {Number} maxSize The maximum size
23328 setMaximumSize : function(maxSize){
23329 this.maxSize = maxSize;
23333 * Sets the initialize size for the resizing element
23334 * @param {Number} size The initial size
23336 setCurrentSize : function(size){
23337 var oldAnimate = this.animate;
23338 this.animate = false;
23339 this.adapter.setElementSize(this, size);
23340 this.animate = oldAnimate;
23344 * Destroy this splitbar.
23345 * @param {Boolean} removeEl True to remove the element
23347 destroy : function(removeEl){
23349 this.shim.remove();
23352 this.proxy.parentNode.removeChild(this.proxy);
23360 * @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.
23362 Roo.SplitBar.createProxy = function(dir){
23363 var proxy = new Roo.Element(document.createElement("div"));
23364 proxy.unselectable();
23365 var cls = 'x-splitbar-proxy';
23366 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23367 document.body.appendChild(proxy.dom);
23372 * @class Roo.SplitBar.BasicLayoutAdapter
23373 * Default Adapter. It assumes the splitter and resizing element are not positioned
23374 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23376 Roo.SplitBar.BasicLayoutAdapter = function(){
23379 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23380 // do nothing for now
23381 init : function(s){
23385 * Called before drag operations to get the current size of the resizing element.
23386 * @param {Roo.SplitBar} s The SplitBar using this adapter
23388 getElementSize : function(s){
23389 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23390 return s.resizingEl.getWidth();
23392 return s.resizingEl.getHeight();
23397 * Called after drag operations to set the size of the resizing element.
23398 * @param {Roo.SplitBar} s The SplitBar using this adapter
23399 * @param {Number} newSize The new size to set
23400 * @param {Function} onComplete A function to be invoked when resizing is complete
23402 setElementSize : function(s, newSize, onComplete){
23403 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23405 s.resizingEl.setWidth(newSize);
23407 onComplete(s, newSize);
23410 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23415 s.resizingEl.setHeight(newSize);
23417 onComplete(s, newSize);
23420 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23427 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23428 * @extends Roo.SplitBar.BasicLayoutAdapter
23429 * Adapter that moves the splitter element to align with the resized sizing element.
23430 * Used with an absolute positioned SplitBar.
23431 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23432 * document.body, make sure you assign an id to the body element.
23434 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23435 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23436 this.container = Roo.get(container);
23439 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23440 init : function(s){
23441 this.basic.init(s);
23444 getElementSize : function(s){
23445 return this.basic.getElementSize(s);
23448 setElementSize : function(s, newSize, onComplete){
23449 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23452 moveSplitter : function(s){
23453 var yes = Roo.SplitBar;
23454 switch(s.placement){
23456 s.el.setX(s.resizingEl.getRight());
23459 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23462 s.el.setY(s.resizingEl.getBottom());
23465 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23472 * Orientation constant - Create a vertical SplitBar
23476 Roo.SplitBar.VERTICAL = 1;
23479 * Orientation constant - Create a horizontal SplitBar
23483 Roo.SplitBar.HORIZONTAL = 2;
23486 * Placement constant - The resizing element is to the left of the splitter element
23490 Roo.SplitBar.LEFT = 1;
23493 * Placement constant - The resizing element is to the right of the splitter element
23497 Roo.SplitBar.RIGHT = 2;
23500 * Placement constant - The resizing element is positioned above the splitter element
23504 Roo.SplitBar.TOP = 3;
23507 * Placement constant - The resizing element is positioned under splitter element
23511 Roo.SplitBar.BOTTOM = 4;
23514 * Ext JS Library 1.1.1
23515 * Copyright(c) 2006-2007, Ext JS, LLC.
23517 * Originally Released Under LGPL - original licence link has changed is not relivant.
23520 * <script type="text/javascript">
23525 * @extends Roo.util.Observable
23526 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23527 * This class also supports single and multi selection modes. <br>
23528 * Create a data model bound view:
23530 var store = new Roo.data.Store(...);
23532 var view = new Roo.View({
23534 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23536 singleSelect: true,
23537 selectedClass: "ydataview-selected",
23541 // listen for node click?
23542 view.on("click", function(vw, index, node, e){
23543 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23547 dataModel.load("foobar.xml");
23549 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23551 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23552 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23554 * Note: old style constructor is still suported (container, template, config)
23557 * Create a new View
23558 * @param {Object} config The config object
23561 Roo.View = function(config, depreciated_tpl, depreciated_config){
23563 if (typeof(depreciated_tpl) == 'undefined') {
23564 // new way.. - universal constructor.
23565 Roo.apply(this, config);
23566 this.el = Roo.get(this.el);
23569 this.el = Roo.get(config);
23570 this.tpl = depreciated_tpl;
23571 Roo.apply(this, depreciated_config);
23575 if(typeof(this.tpl) == "string"){
23576 this.tpl = new Roo.Template(this.tpl);
23578 // support xtype ctors..
23579 this.tpl = new Roo.factory(this.tpl, Roo);
23583 this.tpl.compile();
23590 * @event beforeclick
23591 * Fires before a click is processed. Returns false to cancel the default action.
23592 * @param {Roo.View} this
23593 * @param {Number} index The index of the target node
23594 * @param {HTMLElement} node The target node
23595 * @param {Roo.EventObject} e The raw event object
23597 "beforeclick" : true,
23600 * Fires when a template node is clicked.
23601 * @param {Roo.View} this
23602 * @param {Number} index The index of the target node
23603 * @param {HTMLElement} node The target node
23604 * @param {Roo.EventObject} e The raw event object
23609 * Fires when a template node is double clicked.
23610 * @param {Roo.View} this
23611 * @param {Number} index The index of the target node
23612 * @param {HTMLElement} node The target node
23613 * @param {Roo.EventObject} e The raw event object
23617 * @event contextmenu
23618 * Fires when a template node is right clicked.
23619 * @param {Roo.View} this
23620 * @param {Number} index The index of the target node
23621 * @param {HTMLElement} node The target node
23622 * @param {Roo.EventObject} e The raw event object
23624 "contextmenu" : true,
23626 * @event selectionchange
23627 * Fires when the selected nodes change.
23628 * @param {Roo.View} this
23629 * @param {Array} selections Array of the selected nodes
23631 "selectionchange" : true,
23634 * @event beforeselect
23635 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23636 * @param {Roo.View} this
23637 * @param {HTMLElement} node The node to be selected
23638 * @param {Array} selections Array of currently selected nodes
23640 "beforeselect" : true
23644 "click": this.onClick,
23645 "dblclick": this.onDblClick,
23646 "contextmenu": this.onContextMenu,
23650 this.selections = [];
23652 this.cmp = new Roo.CompositeElementLite([]);
23654 this.store = Roo.factory(this.store, Roo.data);
23655 this.setStore(this.store, true);
23657 Roo.View.superclass.constructor.call(this);
23660 Roo.extend(Roo.View, Roo.util.Observable, {
23663 * @cfg {Roo.data.Store} store Data store to load data from.
23668 * @cfg {String|Roo.Element} el The container element.
23673 * @cfg {String|Roo.Template} tpl The template used by this View
23678 * @cfg {String} selectedClass The css class to add to selected nodes
23680 selectedClass : "x-view-selected",
23682 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23686 * @cfg {Boolean} multiSelect Allow multiple selection
23689 multiSelect : false,
23691 * @cfg {Boolean} singleSelect Allow single selection
23693 singleSelect: false,
23696 * Returns the element this view is bound to.
23697 * @return {Roo.Element}
23699 getEl : function(){
23704 * Refreshes the view.
23706 refresh : function(){
23708 this.clearSelections();
23709 this.el.update("");
23711 var records = this.store.getRange();
23712 if(records.length < 1){
23713 this.el.update(this.emptyText);
23716 for(var i = 0, len = records.length; i < len; i++){
23717 var data = this.prepareData(records[i].data, i, records[i]);
23718 html[html.length] = t.apply(data);
23720 this.el.update(html.join(""));
23721 this.nodes = this.el.dom.childNodes;
23722 this.updateIndexes(0);
23726 * Function to override to reformat the data that is sent to
23727 * the template for each node.
23728 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23729 * a JSON object for an UpdateManager bound view).
23731 prepareData : function(data){
23735 onUpdate : function(ds, record){
23736 this.clearSelections();
23737 var index = this.store.indexOf(record);
23738 var n = this.nodes[index];
23739 this.tpl.insertBefore(n, this.prepareData(record.data));
23740 n.parentNode.removeChild(n);
23741 this.updateIndexes(index, index);
23744 onAdd : function(ds, records, index){
23745 this.clearSelections();
23746 if(this.nodes.length == 0){
23750 var n = this.nodes[index];
23751 for(var i = 0, len = records.length; i < len; i++){
23752 var d = this.prepareData(records[i].data);
23754 this.tpl.insertBefore(n, d);
23756 this.tpl.append(this.el, d);
23759 this.updateIndexes(index);
23762 onRemove : function(ds, record, index){
23763 this.clearSelections();
23764 this.el.dom.removeChild(this.nodes[index]);
23765 this.updateIndexes(index);
23769 * Refresh an individual node.
23770 * @param {Number} index
23772 refreshNode : function(index){
23773 this.onUpdate(this.store, this.store.getAt(index));
23776 updateIndexes : function(startIndex, endIndex){
23777 var ns = this.nodes;
23778 startIndex = startIndex || 0;
23779 endIndex = endIndex || ns.length - 1;
23780 for(var i = startIndex; i <= endIndex; i++){
23781 ns[i].nodeIndex = i;
23786 * Changes the data store this view uses and refresh the view.
23787 * @param {Store} store
23789 setStore : function(store, initial){
23790 if(!initial && this.store){
23791 this.store.un("datachanged", this.refresh);
23792 this.store.un("add", this.onAdd);
23793 this.store.un("remove", this.onRemove);
23794 this.store.un("update", this.onUpdate);
23795 this.store.un("clear", this.refresh);
23799 store.on("datachanged", this.refresh, this);
23800 store.on("add", this.onAdd, this);
23801 store.on("remove", this.onRemove, this);
23802 store.on("update", this.onUpdate, this);
23803 store.on("clear", this.refresh, this);
23812 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23813 * @param {HTMLElement} node
23814 * @return {HTMLElement} The template node
23816 findItemFromChild : function(node){
23817 var el = this.el.dom;
23818 if(!node || node.parentNode == el){
23821 var p = node.parentNode;
23822 while(p && p != el){
23823 if(p.parentNode == el){
23832 onClick : function(e){
23833 var item = this.findItemFromChild(e.getTarget());
23835 var index = this.indexOf(item);
23836 if(this.onItemClick(item, index, e) !== false){
23837 this.fireEvent("click", this, index, item, e);
23840 this.clearSelections();
23845 onContextMenu : function(e){
23846 var item = this.findItemFromChild(e.getTarget());
23848 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23853 onDblClick : function(e){
23854 var item = this.findItemFromChild(e.getTarget());
23856 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23860 onItemClick : function(item, index, e){
23861 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23864 if(this.multiSelect || this.singleSelect){
23865 if(this.multiSelect && e.shiftKey && this.lastSelection){
23866 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23868 this.select(item, this.multiSelect && e.ctrlKey);
23869 this.lastSelection = item;
23871 e.preventDefault();
23877 * Get the number of selected nodes.
23880 getSelectionCount : function(){
23881 return this.selections.length;
23885 * Get the currently selected nodes.
23886 * @return {Array} An array of HTMLElements
23888 getSelectedNodes : function(){
23889 return this.selections;
23893 * Get the indexes of the selected nodes.
23896 getSelectedIndexes : function(){
23897 var indexes = [], s = this.selections;
23898 for(var i = 0, len = s.length; i < len; i++){
23899 indexes.push(s[i].nodeIndex);
23905 * Clear all selections
23906 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23908 clearSelections : function(suppressEvent){
23909 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23910 this.cmp.elements = this.selections;
23911 this.cmp.removeClass(this.selectedClass);
23912 this.selections = [];
23913 if(!suppressEvent){
23914 this.fireEvent("selectionchange", this, this.selections);
23920 * Returns true if the passed node is selected
23921 * @param {HTMLElement/Number} node The node or node index
23922 * @return {Boolean}
23924 isSelected : function(node){
23925 var s = this.selections;
23929 node = this.getNode(node);
23930 return s.indexOf(node) !== -1;
23935 * @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
23936 * @param {Boolean} keepExisting (optional) true to keep existing selections
23937 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23939 select : function(nodeInfo, keepExisting, suppressEvent){
23940 if(nodeInfo instanceof Array){
23942 this.clearSelections(true);
23944 for(var i = 0, len = nodeInfo.length; i < len; i++){
23945 this.select(nodeInfo[i], true, true);
23948 var node = this.getNode(nodeInfo);
23949 if(node && !this.isSelected(node)){
23951 this.clearSelections(true);
23953 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23954 Roo.fly(node).addClass(this.selectedClass);
23955 this.selections.push(node);
23956 if(!suppressEvent){
23957 this.fireEvent("selectionchange", this, this.selections);
23965 * Gets a template node.
23966 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23967 * @return {HTMLElement} The node or null if it wasn't found
23969 getNode : function(nodeInfo){
23970 if(typeof nodeInfo == "string"){
23971 return document.getElementById(nodeInfo);
23972 }else if(typeof nodeInfo == "number"){
23973 return this.nodes[nodeInfo];
23979 * Gets a range template nodes.
23980 * @param {Number} startIndex
23981 * @param {Number} endIndex
23982 * @return {Array} An array of nodes
23984 getNodes : function(start, end){
23985 var ns = this.nodes;
23986 start = start || 0;
23987 end = typeof end == "undefined" ? ns.length - 1 : end;
23990 for(var i = start; i <= end; i++){
23994 for(var i = start; i >= end; i--){
24002 * Finds the index of the passed node
24003 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24004 * @return {Number} The index of the node or -1
24006 indexOf : function(node){
24007 node = this.getNode(node);
24008 if(typeof node.nodeIndex == "number"){
24009 return node.nodeIndex;
24011 var ns = this.nodes;
24012 for(var i = 0, len = ns.length; i < len; i++){
24022 * Ext JS Library 1.1.1
24023 * Copyright(c) 2006-2007, Ext JS, LLC.
24025 * Originally Released Under LGPL - original licence link has changed is not relivant.
24028 * <script type="text/javascript">
24032 * @class Roo.JsonView
24033 * @extends Roo.View
24034 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24036 var view = new Roo.JsonView({
24037 container: "my-element",
24038 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24043 // listen for node click?
24044 view.on("click", function(vw, index, node, e){
24045 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24048 // direct load of JSON data
24049 view.load("foobar.php");
24051 // Example from my blog list
24052 var tpl = new Roo.Template(
24053 '<div class="entry">' +
24054 '<a class="entry-title" href="{link}">{title}</a>' +
24055 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24056 "</div><hr />"
24059 var moreView = new Roo.JsonView({
24060 container : "entry-list",
24064 moreView.on("beforerender", this.sortEntries, this);
24066 url: "/blog/get-posts.php",
24067 params: "allposts=true",
24068 text: "Loading Blog Entries..."
24072 * Note: old code is supported with arguments : (container, template, config)
24076 * Create a new JsonView
24078 * @param {Object} config The config object
24081 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24084 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24086 var um = this.el.getUpdateManager();
24087 um.setRenderer(this);
24088 um.on("update", this.onLoad, this);
24089 um.on("failure", this.onLoadException, this);
24092 * @event beforerender
24093 * Fires before rendering of the downloaded JSON data.
24094 * @param {Roo.JsonView} this
24095 * @param {Object} data The JSON data loaded
24099 * Fires when data is loaded.
24100 * @param {Roo.JsonView} this
24101 * @param {Object} data The JSON data loaded
24102 * @param {Object} response The raw Connect response object
24105 * @event loadexception
24106 * Fires when loading fails.
24107 * @param {Roo.JsonView} this
24108 * @param {Object} response The raw Connect response object
24111 'beforerender' : true,
24113 'loadexception' : true
24116 Roo.extend(Roo.JsonView, Roo.View, {
24118 * @type {String} The root property in the loaded JSON object that contains the data
24123 * Refreshes the view.
24125 refresh : function(){
24126 this.clearSelections();
24127 this.el.update("");
24129 var o = this.jsonData;
24130 if(o && o.length > 0){
24131 for(var i = 0, len = o.length; i < len; i++){
24132 var data = this.prepareData(o[i], i, o);
24133 html[html.length] = this.tpl.apply(data);
24136 html.push(this.emptyText);
24138 this.el.update(html.join(""));
24139 this.nodes = this.el.dom.childNodes;
24140 this.updateIndexes(0);
24144 * 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.
24145 * @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:
24148 url: "your-url.php",
24149 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24150 callback: yourFunction,
24151 scope: yourObject, //(optional scope)
24154 text: "Loading...",
24159 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24160 * 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.
24161 * @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}
24162 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24163 * @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.
24166 var um = this.el.getUpdateManager();
24167 um.update.apply(um, arguments);
24170 render : function(el, response){
24171 this.clearSelections();
24172 this.el.update("");
24175 o = Roo.util.JSON.decode(response.responseText);
24178 o = o[this.jsonRoot];
24183 * The current JSON data or null
24186 this.beforeRender();
24191 * Get the number of records in the current JSON dataset
24194 getCount : function(){
24195 return this.jsonData ? this.jsonData.length : 0;
24199 * Returns the JSON object for the specified node(s)
24200 * @param {HTMLElement/Array} node The node or an array of nodes
24201 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24202 * you get the JSON object for the node
24204 getNodeData : function(node){
24205 if(node instanceof Array){
24207 for(var i = 0, len = node.length; i < len; i++){
24208 data.push(this.getNodeData(node[i]));
24212 return this.jsonData[this.indexOf(node)] || null;
24215 beforeRender : function(){
24216 this.snapshot = this.jsonData;
24218 this.sort.apply(this, this.sortInfo);
24220 this.fireEvent("beforerender", this, this.jsonData);
24223 onLoad : function(el, o){
24224 this.fireEvent("load", this, this.jsonData, o);
24227 onLoadException : function(el, o){
24228 this.fireEvent("loadexception", this, o);
24232 * Filter the data by a specific property.
24233 * @param {String} property A property on your JSON objects
24234 * @param {String/RegExp} value Either string that the property values
24235 * should start with, or a RegExp to test against the property
24237 filter : function(property, value){
24240 var ss = this.snapshot;
24241 if(typeof value == "string"){
24242 var vlen = value.length;
24244 this.clearFilter();
24247 value = value.toLowerCase();
24248 for(var i = 0, len = ss.length; i < len; i++){
24250 if(o[property].substr(0, vlen).toLowerCase() == value){
24254 } else if(value.exec){ // regex?
24255 for(var i = 0, len = ss.length; i < len; i++){
24257 if(value.test(o[property])){
24264 this.jsonData = data;
24270 * Filter by a function. The passed function will be called with each
24271 * object in the current dataset. If the function returns true the value is kept,
24272 * otherwise it is filtered.
24273 * @param {Function} fn
24274 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24276 filterBy : function(fn, scope){
24279 var ss = this.snapshot;
24280 for(var i = 0, len = ss.length; i < len; i++){
24282 if(fn.call(scope || this, o)){
24286 this.jsonData = data;
24292 * Clears the current filter.
24294 clearFilter : function(){
24295 if(this.snapshot && this.jsonData != this.snapshot){
24296 this.jsonData = this.snapshot;
24303 * Sorts the data for this view and refreshes it.
24304 * @param {String} property A property on your JSON objects to sort on
24305 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24306 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24308 sort : function(property, dir, sortType){
24309 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24312 var dsc = dir && dir.toLowerCase() == "desc";
24313 var f = function(o1, o2){
24314 var v1 = sortType ? sortType(o1[p]) : o1[p];
24315 var v2 = sortType ? sortType(o2[p]) : o2[p];
24318 return dsc ? +1 : -1;
24319 } else if(v1 > v2){
24320 return dsc ? -1 : +1;
24325 this.jsonData.sort(f);
24327 if(this.jsonData != this.snapshot){
24328 this.snapshot.sort(f);
24334 * Ext JS Library 1.1.1
24335 * Copyright(c) 2006-2007, Ext JS, LLC.
24337 * Originally Released Under LGPL - original licence link has changed is not relivant.
24340 * <script type="text/javascript">
24345 * @class Roo.ColorPalette
24346 * @extends Roo.Component
24347 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24348 * Here's an example of typical usage:
24350 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24351 cp.render('my-div');
24353 cp.on('select', function(palette, selColor){
24354 // do something with selColor
24358 * Create a new ColorPalette
24359 * @param {Object} config The config object
24361 Roo.ColorPalette = function(config){
24362 Roo.ColorPalette.superclass.constructor.call(this, config);
24366 * Fires when a color is selected
24367 * @param {ColorPalette} this
24368 * @param {String} color The 6-digit color hex code (without the # symbol)
24374 this.on("select", this.handler, this.scope, true);
24377 Roo.extend(Roo.ColorPalette, Roo.Component, {
24379 * @cfg {String} itemCls
24380 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24382 itemCls : "x-color-palette",
24384 * @cfg {String} value
24385 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24386 * the hex codes are case-sensitive.
24389 clickEvent:'click',
24391 ctype: "Roo.ColorPalette",
24394 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24396 allowReselect : false,
24399 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24400 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24401 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24402 * of colors with the width setting until the box is symmetrical.</p>
24403 * <p>You can override individual colors if needed:</p>
24405 var cp = new Roo.ColorPalette();
24406 cp.colors[0] = "FF0000"; // change the first box to red
24409 Or you can provide a custom array of your own for complete control:
24411 var cp = new Roo.ColorPalette();
24412 cp.colors = ["000000", "993300", "333300"];
24417 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24418 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24419 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24420 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24421 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24425 onRender : function(container, position){
24426 var t = new Roo.MasterTemplate(
24427 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24429 var c = this.colors;
24430 for(var i = 0, len = c.length; i < len; i++){
24433 var el = document.createElement("div");
24434 el.className = this.itemCls;
24436 container.dom.insertBefore(el, position);
24437 this.el = Roo.get(el);
24438 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24439 if(this.clickEvent != 'click'){
24440 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24445 afterRender : function(){
24446 Roo.ColorPalette.superclass.afterRender.call(this);
24448 var s = this.value;
24455 handleClick : function(e, t){
24456 e.preventDefault();
24457 if(!this.disabled){
24458 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24459 this.select(c.toUpperCase());
24464 * Selects the specified color in the palette (fires the select event)
24465 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24467 select : function(color){
24468 color = color.replace("#", "");
24469 if(color != this.value || this.allowReselect){
24472 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24474 el.child("a.color-"+color).addClass("x-color-palette-sel");
24475 this.value = color;
24476 this.fireEvent("select", this, color);
24481 * Ext JS Library 1.1.1
24482 * Copyright(c) 2006-2007, Ext JS, LLC.
24484 * Originally Released Under LGPL - original licence link has changed is not relivant.
24487 * <script type="text/javascript">
24491 * @class Roo.DatePicker
24492 * @extends Roo.Component
24493 * Simple date picker class.
24495 * Create a new DatePicker
24496 * @param {Object} config The config object
24498 Roo.DatePicker = function(config){
24499 Roo.DatePicker.superclass.constructor.call(this, config);
24501 this.value = config && config.value ?
24502 config.value.clearTime() : new Date().clearTime();
24507 * Fires when a date is selected
24508 * @param {DatePicker} this
24509 * @param {Date} date The selected date
24515 this.on("select", this.handler, this.scope || this);
24517 // build the disabledDatesRE
24518 if(!this.disabledDatesRE && this.disabledDates){
24519 var dd = this.disabledDates;
24521 for(var i = 0; i < dd.length; i++){
24523 if(i != dd.length-1) re += "|";
24525 this.disabledDatesRE = new RegExp(re + ")");
24529 Roo.extend(Roo.DatePicker, Roo.Component, {
24531 * @cfg {String} todayText
24532 * The text to display on the button that selects the current date (defaults to "Today")
24534 todayText : "Today",
24536 * @cfg {String} okText
24537 * The text to display on the ok button
24539 okText : " OK ", //   to give the user extra clicking room
24541 * @cfg {String} cancelText
24542 * The text to display on the cancel button
24544 cancelText : "Cancel",
24546 * @cfg {String} todayTip
24547 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24549 todayTip : "{0} (Spacebar)",
24551 * @cfg {Date} minDate
24552 * Minimum allowable date (JavaScript date object, defaults to null)
24556 * @cfg {Date} maxDate
24557 * Maximum allowable date (JavaScript date object, defaults to null)
24561 * @cfg {String} minText
24562 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24564 minText : "This date is before the minimum date",
24566 * @cfg {String} maxText
24567 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24569 maxText : "This date is after the maximum date",
24571 * @cfg {String} format
24572 * The default date format string which can be overriden for localization support. The format must be
24573 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24577 * @cfg {Array} disabledDays
24578 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24580 disabledDays : null,
24582 * @cfg {String} disabledDaysText
24583 * The tooltip to display when the date falls on a disabled day (defaults to "")
24585 disabledDaysText : "",
24587 * @cfg {RegExp} disabledDatesRE
24588 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24590 disabledDatesRE : null,
24592 * @cfg {String} disabledDatesText
24593 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24595 disabledDatesText : "",
24597 * @cfg {Boolean} constrainToViewport
24598 * True to constrain the date picker to the viewport (defaults to true)
24600 constrainToViewport : true,
24602 * @cfg {Array} monthNames
24603 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24605 monthNames : Date.monthNames,
24607 * @cfg {Array} dayNames
24608 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24610 dayNames : Date.dayNames,
24612 * @cfg {String} nextText
24613 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24615 nextText: 'Next Month (Control+Right)',
24617 * @cfg {String} prevText
24618 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24620 prevText: 'Previous Month (Control+Left)',
24622 * @cfg {String} monthYearText
24623 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24625 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24627 * @cfg {Number} startDay
24628 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24632 * @cfg {Bool} showClear
24633 * Show a clear button (usefull for date form elements that can be blank.)
24639 * Sets the value of the date field
24640 * @param {Date} value The date to set
24642 setValue : function(value){
24643 var old = this.value;
24644 this.value = value.clearTime(true);
24646 this.update(this.value);
24651 * Gets the current selected value of the date field
24652 * @return {Date} The selected date
24654 getValue : function(){
24659 focus : function(){
24661 this.update(this.activeDate);
24666 onRender : function(container, position){
24668 '<table cellspacing="0">',
24669 '<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>',
24670 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24671 var dn = this.dayNames;
24672 for(var i = 0; i < 7; i++){
24673 var d = this.startDay+i;
24677 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24679 m[m.length] = "</tr></thead><tbody><tr>";
24680 for(var i = 0; i < 42; i++) {
24681 if(i % 7 == 0 && i != 0){
24682 m[m.length] = "</tr><tr>";
24684 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24686 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24687 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24689 var el = document.createElement("div");
24690 el.className = "x-date-picker";
24691 el.innerHTML = m.join("");
24693 container.dom.insertBefore(el, position);
24695 this.el = Roo.get(el);
24696 this.eventEl = Roo.get(el.firstChild);
24698 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24699 handler: this.showPrevMonth,
24701 preventDefault:true,
24705 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24706 handler: this.showNextMonth,
24708 preventDefault:true,
24712 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24714 this.monthPicker = this.el.down('div.x-date-mp');
24715 this.monthPicker.enableDisplayMode('block');
24717 var kn = new Roo.KeyNav(this.eventEl, {
24718 "left" : function(e){
24720 this.showPrevMonth() :
24721 this.update(this.activeDate.add("d", -1));
24724 "right" : function(e){
24726 this.showNextMonth() :
24727 this.update(this.activeDate.add("d", 1));
24730 "up" : function(e){
24732 this.showNextYear() :
24733 this.update(this.activeDate.add("d", -7));
24736 "down" : function(e){
24738 this.showPrevYear() :
24739 this.update(this.activeDate.add("d", 7));
24742 "pageUp" : function(e){
24743 this.showNextMonth();
24746 "pageDown" : function(e){
24747 this.showPrevMonth();
24750 "enter" : function(e){
24751 e.stopPropagation();
24758 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24760 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24762 this.el.unselectable();
24764 this.cells = this.el.select("table.x-date-inner tbody td");
24765 this.textNodes = this.el.query("table.x-date-inner tbody span");
24767 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24769 tooltip: this.monthYearText
24772 this.mbtn.on('click', this.showMonthPicker, this);
24773 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24776 var today = (new Date()).dateFormat(this.format);
24778 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24779 if (this.showClear) {
24780 baseTb.add( new Roo.Toolbar.Fill());
24783 text: String.format(this.todayText, today),
24784 tooltip: String.format(this.todayTip, today),
24785 handler: this.selectToday,
24789 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24792 if (this.showClear) {
24794 baseTb.add( new Roo.Toolbar.Fill());
24797 cls: 'x-btn-icon x-btn-clear',
24798 handler: function() {
24800 this.fireEvent("select", this, '');
24810 this.update(this.value);
24813 createMonthPicker : function(){
24814 if(!this.monthPicker.dom.firstChild){
24815 var buf = ['<table border="0" cellspacing="0">'];
24816 for(var i = 0; i < 6; i++){
24818 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24819 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24821 '<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>' :
24822 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24826 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24828 '</button><button type="button" class="x-date-mp-cancel">',
24830 '</button></td></tr>',
24833 this.monthPicker.update(buf.join(''));
24834 this.monthPicker.on('click', this.onMonthClick, this);
24835 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24837 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24838 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24840 this.mpMonths.each(function(m, a, i){
24843 m.dom.xmonth = 5 + Math.round(i * .5);
24845 m.dom.xmonth = Math.round((i-1) * .5);
24851 showMonthPicker : function(){
24852 this.createMonthPicker();
24853 var size = this.el.getSize();
24854 this.monthPicker.setSize(size);
24855 this.monthPicker.child('table').setSize(size);
24857 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24858 this.updateMPMonth(this.mpSelMonth);
24859 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24860 this.updateMPYear(this.mpSelYear);
24862 this.monthPicker.slideIn('t', {duration:.2});
24865 updateMPYear : function(y){
24867 var ys = this.mpYears.elements;
24868 for(var i = 1; i <= 10; i++){
24869 var td = ys[i-1], y2;
24871 y2 = y + Math.round(i * .5);
24872 td.firstChild.innerHTML = y2;
24875 y2 = y - (5-Math.round(i * .5));
24876 td.firstChild.innerHTML = y2;
24879 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24883 updateMPMonth : function(sm){
24884 this.mpMonths.each(function(m, a, i){
24885 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24889 selectMPMonth: function(m){
24893 onMonthClick : function(e, t){
24895 var el = new Roo.Element(t), pn;
24896 if(el.is('button.x-date-mp-cancel')){
24897 this.hideMonthPicker();
24899 else if(el.is('button.x-date-mp-ok')){
24900 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24901 this.hideMonthPicker();
24903 else if(pn = el.up('td.x-date-mp-month', 2)){
24904 this.mpMonths.removeClass('x-date-mp-sel');
24905 pn.addClass('x-date-mp-sel');
24906 this.mpSelMonth = pn.dom.xmonth;
24908 else if(pn = el.up('td.x-date-mp-year', 2)){
24909 this.mpYears.removeClass('x-date-mp-sel');
24910 pn.addClass('x-date-mp-sel');
24911 this.mpSelYear = pn.dom.xyear;
24913 else if(el.is('a.x-date-mp-prev')){
24914 this.updateMPYear(this.mpyear-10);
24916 else if(el.is('a.x-date-mp-next')){
24917 this.updateMPYear(this.mpyear+10);
24921 onMonthDblClick : function(e, t){
24923 var el = new Roo.Element(t), pn;
24924 if(pn = el.up('td.x-date-mp-month', 2)){
24925 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24926 this.hideMonthPicker();
24928 else if(pn = el.up('td.x-date-mp-year', 2)){
24929 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24930 this.hideMonthPicker();
24934 hideMonthPicker : function(disableAnim){
24935 if(this.monthPicker){
24936 if(disableAnim === true){
24937 this.monthPicker.hide();
24939 this.monthPicker.slideOut('t', {duration:.2});
24945 showPrevMonth : function(e){
24946 this.update(this.activeDate.add("mo", -1));
24950 showNextMonth : function(e){
24951 this.update(this.activeDate.add("mo", 1));
24955 showPrevYear : function(){
24956 this.update(this.activeDate.add("y", -1));
24960 showNextYear : function(){
24961 this.update(this.activeDate.add("y", 1));
24965 handleMouseWheel : function(e){
24966 var delta = e.getWheelDelta();
24968 this.showPrevMonth();
24970 } else if(delta < 0){
24971 this.showNextMonth();
24977 handleDateClick : function(e, t){
24979 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24980 this.setValue(new Date(t.dateValue));
24981 this.fireEvent("select", this, this.value);
24986 selectToday : function(){
24987 this.setValue(new Date().clearTime());
24988 this.fireEvent("select", this, this.value);
24992 update : function(date){
24993 var vd = this.activeDate;
24994 this.activeDate = date;
24996 var t = date.getTime();
24997 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24998 this.cells.removeClass("x-date-selected");
24999 this.cells.each(function(c){
25000 if(c.dom.firstChild.dateValue == t){
25001 c.addClass("x-date-selected");
25002 setTimeout(function(){
25003 try{c.dom.firstChild.focus();}catch(e){}
25011 var days = date.getDaysInMonth();
25012 var firstOfMonth = date.getFirstDateOfMonth();
25013 var startingPos = firstOfMonth.getDay()-this.startDay;
25015 if(startingPos <= this.startDay){
25019 var pm = date.add("mo", -1);
25020 var prevStart = pm.getDaysInMonth()-startingPos;
25022 var cells = this.cells.elements;
25023 var textEls = this.textNodes;
25024 days += startingPos;
25026 // convert everything to numbers so it's fast
25027 var day = 86400000;
25028 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25029 var today = new Date().clearTime().getTime();
25030 var sel = date.clearTime().getTime();
25031 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25032 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25033 var ddMatch = this.disabledDatesRE;
25034 var ddText = this.disabledDatesText;
25035 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25036 var ddaysText = this.disabledDaysText;
25037 var format = this.format;
25039 var setCellClass = function(cal, cell){
25041 var t = d.getTime();
25042 cell.firstChild.dateValue = t;
25044 cell.className += " x-date-today";
25045 cell.title = cal.todayText;
25048 cell.className += " x-date-selected";
25049 setTimeout(function(){
25050 try{cell.firstChild.focus();}catch(e){}
25055 cell.className = " x-date-disabled";
25056 cell.title = cal.minText;
25060 cell.className = " x-date-disabled";
25061 cell.title = cal.maxText;
25065 if(ddays.indexOf(d.getDay()) != -1){
25066 cell.title = ddaysText;
25067 cell.className = " x-date-disabled";
25070 if(ddMatch && format){
25071 var fvalue = d.dateFormat(format);
25072 if(ddMatch.test(fvalue)){
25073 cell.title = ddText.replace("%0", fvalue);
25074 cell.className = " x-date-disabled";
25080 for(; i < startingPos; i++) {
25081 textEls[i].innerHTML = (++prevStart);
25082 d.setDate(d.getDate()+1);
25083 cells[i].className = "x-date-prevday";
25084 setCellClass(this, cells[i]);
25086 for(; i < days; i++){
25087 intDay = i - startingPos + 1;
25088 textEls[i].innerHTML = (intDay);
25089 d.setDate(d.getDate()+1);
25090 cells[i].className = "x-date-active";
25091 setCellClass(this, cells[i]);
25094 for(; i < 42; i++) {
25095 textEls[i].innerHTML = (++extraDays);
25096 d.setDate(d.getDate()+1);
25097 cells[i].className = "x-date-nextday";
25098 setCellClass(this, cells[i]);
25101 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25103 if(!this.internalRender){
25104 var main = this.el.dom.firstChild;
25105 var w = main.offsetWidth;
25106 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25107 Roo.fly(main).setWidth(w);
25108 this.internalRender = true;
25109 // opera does not respect the auto grow header center column
25110 // then, after it gets a width opera refuses to recalculate
25111 // without a second pass
25112 if(Roo.isOpera && !this.secondPass){
25113 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25114 this.secondPass = true;
25115 this.update.defer(10, this, [date]);
25121 * Ext JS Library 1.1.1
25122 * Copyright(c) 2006-2007, Ext JS, LLC.
25124 * Originally Released Under LGPL - original licence link has changed is not relivant.
25127 * <script type="text/javascript">
25130 * @class Roo.TabPanel
25131 * @extends Roo.util.Observable
25132 * A lightweight tab container.
25136 // basic tabs 1, built from existing content
25137 var tabs = new Roo.TabPanel("tabs1");
25138 tabs.addTab("script", "View Script");
25139 tabs.addTab("markup", "View Markup");
25140 tabs.activate("script");
25142 // more advanced tabs, built from javascript
25143 var jtabs = new Roo.TabPanel("jtabs");
25144 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25146 // set up the UpdateManager
25147 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25148 var updater = tab2.getUpdateManager();
25149 updater.setDefaultUrl("ajax1.htm");
25150 tab2.on('activate', updater.refresh, updater, true);
25152 // Use setUrl for Ajax loading
25153 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25154 tab3.setUrl("ajax2.htm", null, true);
25157 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25160 jtabs.activate("jtabs-1");
25163 * Create a new TabPanel.
25164 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25165 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25167 Roo.TabPanel = function(container, config){
25169 * The container element for this TabPanel.
25170 * @type Roo.Element
25172 this.el = Roo.get(container, true);
25174 if(typeof config == "boolean"){
25175 this.tabPosition = config ? "bottom" : "top";
25177 Roo.apply(this, config);
25180 if(this.tabPosition == "bottom"){
25181 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25182 this.el.addClass("x-tabs-bottom");
25184 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25185 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25186 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25188 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25190 if(this.tabPosition != "bottom"){
25191 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25192 * @type Roo.Element
25194 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25195 this.el.addClass("x-tabs-top");
25199 this.bodyEl.setStyle("position", "relative");
25201 this.active = null;
25202 this.activateDelegate = this.activate.createDelegate(this);
25207 * Fires when the active tab changes
25208 * @param {Roo.TabPanel} this
25209 * @param {Roo.TabPanelItem} activePanel The new active tab
25213 * @event beforetabchange
25214 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25215 * @param {Roo.TabPanel} this
25216 * @param {Object} e Set cancel to true on this object to cancel the tab change
25217 * @param {Roo.TabPanelItem} tab The tab being changed to
25219 "beforetabchange" : true
25222 Roo.EventManager.onWindowResize(this.onResize, this);
25223 this.cpad = this.el.getPadding("lr");
25224 this.hiddenCount = 0;
25226 Roo.TabPanel.superclass.constructor.call(this);
25229 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25231 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25233 tabPosition : "top",
25235 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25237 currentTabWidth : 0,
25239 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25243 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25247 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25249 preferredTabWidth : 175,
25251 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25253 resizeTabs : false,
25255 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25257 monitorResize : true,
25260 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25261 * @param {String} id The id of the div to use <b>or create</b>
25262 * @param {String} text The text for the tab
25263 * @param {String} content (optional) Content to put in the TabPanelItem body
25264 * @param {Boolean} closable (optional) True to create a close icon on the tab
25265 * @return {Roo.TabPanelItem} The created TabPanelItem
25267 addTab : function(id, text, content, closable){
25268 var item = new Roo.TabPanelItem(this, id, text, closable);
25269 this.addTabItem(item);
25271 item.setContent(content);
25277 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25278 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25279 * @return {Roo.TabPanelItem}
25281 getTab : function(id){
25282 return this.items[id];
25286 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25287 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25289 hideTab : function(id){
25290 var t = this.items[id];
25293 this.hiddenCount++;
25294 this.autoSizeTabs();
25299 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25300 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25302 unhideTab : function(id){
25303 var t = this.items[id];
25305 t.setHidden(false);
25306 this.hiddenCount--;
25307 this.autoSizeTabs();
25312 * Adds an existing {@link Roo.TabPanelItem}.
25313 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25315 addTabItem : function(item){
25316 this.items[item.id] = item;
25317 this.items.push(item);
25318 if(this.resizeTabs){
25319 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25320 this.autoSizeTabs();
25327 * Removes a {@link Roo.TabPanelItem}.
25328 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25330 removeTab : function(id){
25331 var items = this.items;
25332 var tab = items[id];
25333 if(!tab) { return; }
25334 var index = items.indexOf(tab);
25335 if(this.active == tab && items.length > 1){
25336 var newTab = this.getNextAvailable(index);
25341 this.stripEl.dom.removeChild(tab.pnode.dom);
25342 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25343 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25345 items.splice(index, 1);
25346 delete this.items[tab.id];
25347 tab.fireEvent("close", tab);
25348 tab.purgeListeners();
25349 this.autoSizeTabs();
25352 getNextAvailable : function(start){
25353 var items = this.items;
25355 // look for a next tab that will slide over to
25356 // replace the one being removed
25357 while(index < items.length){
25358 var item = items[++index];
25359 if(item && !item.isHidden()){
25363 // if one isn't found select the previous tab (on the left)
25366 var item = items[--index];
25367 if(item && !item.isHidden()){
25375 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25376 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25378 disableTab : function(id){
25379 var tab = this.items[id];
25380 if(tab && this.active != tab){
25386 * Enables a {@link Roo.TabPanelItem} that is disabled.
25387 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25389 enableTab : function(id){
25390 var tab = this.items[id];
25395 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25396 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25397 * @return {Roo.TabPanelItem} The TabPanelItem.
25399 activate : function(id){
25400 var tab = this.items[id];
25404 if(tab == this.active || tab.disabled){
25408 this.fireEvent("beforetabchange", this, e, tab);
25409 if(e.cancel !== true && !tab.disabled){
25411 this.active.hide();
25413 this.active = this.items[id];
25414 this.active.show();
25415 this.fireEvent("tabchange", this, this.active);
25421 * Gets the active {@link Roo.TabPanelItem}.
25422 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25424 getActiveTab : function(){
25425 return this.active;
25429 * Updates the tab body element to fit the height of the container element
25430 * for overflow scrolling
25431 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25433 syncHeight : function(targetHeight){
25434 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25435 var bm = this.bodyEl.getMargins();
25436 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25437 this.bodyEl.setHeight(newHeight);
25441 onResize : function(){
25442 if(this.monitorResize){
25443 this.autoSizeTabs();
25448 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25450 beginUpdate : function(){
25451 this.updating = true;
25455 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25457 endUpdate : function(){
25458 this.updating = false;
25459 this.autoSizeTabs();
25463 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25465 autoSizeTabs : function(){
25466 var count = this.items.length;
25467 var vcount = count - this.hiddenCount;
25468 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25469 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25470 var availWidth = Math.floor(w / vcount);
25471 var b = this.stripBody;
25472 if(b.getWidth() > w){
25473 var tabs = this.items;
25474 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25475 if(availWidth < this.minTabWidth){
25476 /*if(!this.sleft){ // incomplete scrolling code
25477 this.createScrollButtons();
25480 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25483 if(this.currentTabWidth < this.preferredTabWidth){
25484 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25490 * Returns the number of tabs in this TabPanel.
25493 getCount : function(){
25494 return this.items.length;
25498 * Resizes all the tabs to the passed width
25499 * @param {Number} The new width
25501 setTabWidth : function(width){
25502 this.currentTabWidth = width;
25503 for(var i = 0, len = this.items.length; i < len; i++) {
25504 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25509 * Destroys this TabPanel
25510 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25512 destroy : function(removeEl){
25513 Roo.EventManager.removeResizeListener(this.onResize, this);
25514 for(var i = 0, len = this.items.length; i < len; i++){
25515 this.items[i].purgeListeners();
25517 if(removeEl === true){
25518 this.el.update("");
25525 * @class Roo.TabPanelItem
25526 * @extends Roo.util.Observable
25527 * Represents an individual item (tab plus body) in a TabPanel.
25528 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25529 * @param {String} id The id of this TabPanelItem
25530 * @param {String} text The text for the tab of this TabPanelItem
25531 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25533 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25535 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25536 * @type Roo.TabPanel
25538 this.tabPanel = tabPanel;
25540 * The id for this TabPanelItem
25545 this.disabled = false;
25549 this.loaded = false;
25550 this.closable = closable;
25553 * The body element for this TabPanelItem.
25554 * @type Roo.Element
25556 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25557 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25558 this.bodyEl.setStyle("display", "block");
25559 this.bodyEl.setStyle("zoom", "1");
25562 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25564 this.el = Roo.get(els.el, true);
25565 this.inner = Roo.get(els.inner, true);
25566 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25567 this.pnode = Roo.get(els.el.parentNode, true);
25568 this.el.on("mousedown", this.onTabMouseDown, this);
25569 this.el.on("click", this.onTabClick, this);
25572 var c = Roo.get(els.close, true);
25573 c.dom.title = this.closeText;
25574 c.addClassOnOver("close-over");
25575 c.on("click", this.closeClick, this);
25581 * Fires when this tab becomes the active tab.
25582 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25583 * @param {Roo.TabPanelItem} this
25587 * @event beforeclose
25588 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25589 * @param {Roo.TabPanelItem} this
25590 * @param {Object} e Set cancel to true on this object to cancel the close.
25592 "beforeclose": true,
25595 * Fires when this tab is closed.
25596 * @param {Roo.TabPanelItem} this
25600 * @event deactivate
25601 * Fires when this tab is no longer the active tab.
25602 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25603 * @param {Roo.TabPanelItem} this
25605 "deactivate" : true
25607 this.hidden = false;
25609 Roo.TabPanelItem.superclass.constructor.call(this);
25612 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25613 purgeListeners : function(){
25614 Roo.util.Observable.prototype.purgeListeners.call(this);
25615 this.el.removeAllListeners();
25618 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25621 this.pnode.addClass("on");
25624 this.tabPanel.stripWrap.repaint();
25626 this.fireEvent("activate", this.tabPanel, this);
25630 * Returns true if this tab is the active tab.
25631 * @return {Boolean}
25633 isActive : function(){
25634 return this.tabPanel.getActiveTab() == this;
25638 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25641 this.pnode.removeClass("on");
25643 this.fireEvent("deactivate", this.tabPanel, this);
25646 hideAction : function(){
25647 this.bodyEl.hide();
25648 this.bodyEl.setStyle("position", "absolute");
25649 this.bodyEl.setLeft("-20000px");
25650 this.bodyEl.setTop("-20000px");
25653 showAction : function(){
25654 this.bodyEl.setStyle("position", "relative");
25655 this.bodyEl.setTop("");
25656 this.bodyEl.setLeft("");
25657 this.bodyEl.show();
25661 * Set the tooltip for the tab.
25662 * @param {String} tooltip The tab's tooltip
25664 setTooltip : function(text){
25665 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25666 this.textEl.dom.qtip = text;
25667 this.textEl.dom.removeAttribute('title');
25669 this.textEl.dom.title = text;
25673 onTabClick : function(e){
25674 e.preventDefault();
25675 this.tabPanel.activate(this.id);
25678 onTabMouseDown : function(e){
25679 e.preventDefault();
25680 this.tabPanel.activate(this.id);
25683 getWidth : function(){
25684 return this.inner.getWidth();
25687 setWidth : function(width){
25688 var iwidth = width - this.pnode.getPadding("lr");
25689 this.inner.setWidth(iwidth);
25690 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25691 this.pnode.setWidth(width);
25695 * Show or hide the tab
25696 * @param {Boolean} hidden True to hide or false to show.
25698 setHidden : function(hidden){
25699 this.hidden = hidden;
25700 this.pnode.setStyle("display", hidden ? "none" : "");
25704 * Returns true if this tab is "hidden"
25705 * @return {Boolean}
25707 isHidden : function(){
25708 return this.hidden;
25712 * Returns the text for this tab
25715 getText : function(){
25719 autoSize : function(){
25720 //this.el.beginMeasure();
25721 this.textEl.setWidth(1);
25722 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25723 //this.el.endMeasure();
25727 * Sets the text for the tab (Note: this also sets the tooltip text)
25728 * @param {String} text The tab's text and tooltip
25730 setText : function(text){
25732 this.textEl.update(text);
25733 this.setTooltip(text);
25734 if(!this.tabPanel.resizeTabs){
25739 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25741 activate : function(){
25742 this.tabPanel.activate(this.id);
25746 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25748 disable : function(){
25749 if(this.tabPanel.active != this){
25750 this.disabled = true;
25751 this.pnode.addClass("disabled");
25756 * Enables this TabPanelItem if it was previously disabled.
25758 enable : function(){
25759 this.disabled = false;
25760 this.pnode.removeClass("disabled");
25764 * Sets the content for this TabPanelItem.
25765 * @param {String} content The content
25766 * @param {Boolean} loadScripts true to look for and load scripts
25768 setContent : function(content, loadScripts){
25769 this.bodyEl.update(content, loadScripts);
25773 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25774 * @return {Roo.UpdateManager} The UpdateManager
25776 getUpdateManager : function(){
25777 return this.bodyEl.getUpdateManager();
25781 * Set a URL to be used to load the content for this TabPanelItem.
25782 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25783 * @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)
25784 * @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)
25785 * @return {Roo.UpdateManager} The UpdateManager
25787 setUrl : function(url, params, loadOnce){
25788 if(this.refreshDelegate){
25789 this.un('activate', this.refreshDelegate);
25791 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25792 this.on("activate", this.refreshDelegate);
25793 return this.bodyEl.getUpdateManager();
25797 _handleRefresh : function(url, params, loadOnce){
25798 if(!loadOnce || !this.loaded){
25799 var updater = this.bodyEl.getUpdateManager();
25800 updater.update(url, params, this._setLoaded.createDelegate(this));
25805 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25806 * Will fail silently if the setUrl method has not been called.
25807 * This does not activate the panel, just updates its content.
25809 refresh : function(){
25810 if(this.refreshDelegate){
25811 this.loaded = false;
25812 this.refreshDelegate();
25817 _setLoaded : function(){
25818 this.loaded = true;
25822 closeClick : function(e){
25825 this.fireEvent("beforeclose", this, o);
25826 if(o.cancel !== true){
25827 this.tabPanel.removeTab(this.id);
25831 * The text displayed in the tooltip for the close icon.
25834 closeText : "Close this tab"
25838 Roo.TabPanel.prototype.createStrip = function(container){
25839 var strip = document.createElement("div");
25840 strip.className = "x-tabs-wrap";
25841 container.appendChild(strip);
25845 Roo.TabPanel.prototype.createStripList = function(strip){
25846 // div wrapper for retard IE
25847 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>';
25848 return strip.firstChild.firstChild.firstChild.firstChild;
25851 Roo.TabPanel.prototype.createBody = function(container){
25852 var body = document.createElement("div");
25853 Roo.id(body, "tab-body");
25854 Roo.fly(body).addClass("x-tabs-body");
25855 container.appendChild(body);
25859 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25860 var body = Roo.getDom(id);
25862 body = document.createElement("div");
25865 Roo.fly(body).addClass("x-tabs-item-body");
25866 bodyEl.insertBefore(body, bodyEl.firstChild);
25870 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25871 var td = document.createElement("td");
25872 stripEl.appendChild(td);
25874 td.className = "x-tabs-closable";
25875 if(!this.closeTpl){
25876 this.closeTpl = new Roo.Template(
25877 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25878 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25879 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25882 var el = this.closeTpl.overwrite(td, {"text": text});
25883 var close = el.getElementsByTagName("div")[0];
25884 var inner = el.getElementsByTagName("em")[0];
25885 return {"el": el, "close": close, "inner": inner};
25888 this.tabTpl = new Roo.Template(
25889 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25890 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25893 var el = this.tabTpl.overwrite(td, {"text": text});
25894 var inner = el.getElementsByTagName("em")[0];
25895 return {"el": el, "inner": inner};
25899 * Ext JS Library 1.1.1
25900 * Copyright(c) 2006-2007, Ext JS, LLC.
25902 * Originally Released Under LGPL - original licence link has changed is not relivant.
25905 * <script type="text/javascript">
25909 * @class Roo.Button
25910 * @extends Roo.util.Observable
25911 * Simple Button class
25912 * @cfg {String} text The button text
25913 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25914 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25915 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25916 * @cfg {Object} scope The scope of the handler
25917 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25918 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25919 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25920 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25921 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25922 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25923 applies if enableToggle = true)
25924 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25925 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25926 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25928 * Create a new button
25929 * @param {Object} config The config object
25931 Roo.Button = function(renderTo, config)
25935 renderTo = config.renderTo || false;
25938 Roo.apply(this, config);
25942 * Fires when this button is clicked
25943 * @param {Button} this
25944 * @param {EventObject} e The click event
25949 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25950 * @param {Button} this
25951 * @param {Boolean} pressed
25956 * Fires when the mouse hovers over the button
25957 * @param {Button} this
25958 * @param {Event} e The event object
25960 'mouseover' : true,
25963 * Fires when the mouse exits the button
25964 * @param {Button} this
25965 * @param {Event} e The event object
25970 * Fires when the button is rendered
25971 * @param {Button} this
25976 this.menu = Roo.menu.MenuMgr.get(this.menu);
25978 // register listeners first!! - so render can be captured..
25979 Roo.util.Observable.call(this);
25981 this.render(renderTo);
25987 Roo.extend(Roo.Button, Roo.util.Observable, {
25993 * Read-only. True if this button is hidden
25998 * Read-only. True if this button is disabled
26003 * Read-only. True if this button is pressed (only if enableToggle = true)
26009 * @cfg {Number} tabIndex
26010 * The DOM tabIndex for this button (defaults to undefined)
26012 tabIndex : undefined,
26015 * @cfg {Boolean} enableToggle
26016 * True to enable pressed/not pressed toggling (defaults to false)
26018 enableToggle: false,
26020 * @cfg {Mixed} menu
26021 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26025 * @cfg {String} menuAlign
26026 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26028 menuAlign : "tl-bl?",
26031 * @cfg {String} iconCls
26032 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26034 iconCls : undefined,
26036 * @cfg {String} type
26037 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26042 menuClassTarget: 'tr',
26045 * @cfg {String} clickEvent
26046 * The type of event to map to the button's event handler (defaults to 'click')
26048 clickEvent : 'click',
26051 * @cfg {Boolean} handleMouseEvents
26052 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26054 handleMouseEvents : true,
26057 * @cfg {String} tooltipType
26058 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26060 tooltipType : 'qtip',
26063 * @cfg {String} cls
26064 * A CSS class to apply to the button's main element.
26068 * @cfg {Roo.Template} template (Optional)
26069 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26070 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26071 * require code modifications if required elements (e.g. a button) aren't present.
26075 render : function(renderTo){
26077 if(this.hideParent){
26078 this.parentEl = Roo.get(renderTo);
26080 if(!this.dhconfig){
26081 if(!this.template){
26082 if(!Roo.Button.buttonTemplate){
26083 // hideous table template
26084 Roo.Button.buttonTemplate = new Roo.Template(
26085 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26086 '<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>',
26087 "</tr></tbody></table>");
26089 this.template = Roo.Button.buttonTemplate;
26091 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26092 var btnEl = btn.child("button:first");
26093 btnEl.on('focus', this.onFocus, this);
26094 btnEl.on('blur', this.onBlur, this);
26096 btn.addClass(this.cls);
26099 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26102 btnEl.addClass(this.iconCls);
26104 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26107 if(this.tabIndex !== undefined){
26108 btnEl.dom.tabIndex = this.tabIndex;
26111 if(typeof this.tooltip == 'object'){
26112 Roo.QuickTips.tips(Roo.apply({
26116 btnEl.dom[this.tooltipType] = this.tooltip;
26120 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26124 this.el.dom.id = this.el.id = this.id;
26127 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26128 this.menu.on("show", this.onMenuShow, this);
26129 this.menu.on("hide", this.onMenuHide, this);
26131 btn.addClass("x-btn");
26132 if(Roo.isIE && !Roo.isIE7){
26133 this.autoWidth.defer(1, this);
26137 if(this.handleMouseEvents){
26138 btn.on("mouseover", this.onMouseOver, this);
26139 btn.on("mouseout", this.onMouseOut, this);
26140 btn.on("mousedown", this.onMouseDown, this);
26142 btn.on(this.clickEvent, this.onClick, this);
26143 //btn.on("mouseup", this.onMouseUp, this);
26150 Roo.ButtonToggleMgr.register(this);
26152 this.el.addClass("x-btn-pressed");
26155 var repeater = new Roo.util.ClickRepeater(btn,
26156 typeof this.repeat == "object" ? this.repeat : {}
26158 repeater.on("click", this.onClick, this);
26161 this.fireEvent('render', this);
26165 * Returns the button's underlying element
26166 * @return {Roo.Element} The element
26168 getEl : function(){
26173 * Destroys this Button and removes any listeners.
26175 destroy : function(){
26176 Roo.ButtonToggleMgr.unregister(this);
26177 this.el.removeAllListeners();
26178 this.purgeListeners();
26183 autoWidth : function(){
26185 this.el.setWidth("auto");
26186 if(Roo.isIE7 && Roo.isStrict){
26187 var ib = this.el.child('button');
26188 if(ib && ib.getWidth() > 20){
26190 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26195 this.el.beginMeasure();
26197 if(this.el.getWidth() < this.minWidth){
26198 this.el.setWidth(this.minWidth);
26201 this.el.endMeasure();
26208 * Assigns this button's click handler
26209 * @param {Function} handler The function to call when the button is clicked
26210 * @param {Object} scope (optional) Scope for the function passed in
26212 setHandler : function(handler, scope){
26213 this.handler = handler;
26214 this.scope = scope;
26218 * Sets this button's text
26219 * @param {String} text The button text
26221 setText : function(text){
26224 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26230 * Gets the text for this button
26231 * @return {String} The button text
26233 getText : function(){
26241 this.hidden = false;
26243 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26251 this.hidden = true;
26253 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26258 * Convenience function for boolean show/hide
26259 * @param {Boolean} visible True to show, false to hide
26261 setVisible: function(visible){
26270 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26271 * @param {Boolean} state (optional) Force a particular state
26273 toggle : function(state){
26274 state = state === undefined ? !this.pressed : state;
26275 if(state != this.pressed){
26277 this.el.addClass("x-btn-pressed");
26278 this.pressed = true;
26279 this.fireEvent("toggle", this, true);
26281 this.el.removeClass("x-btn-pressed");
26282 this.pressed = false;
26283 this.fireEvent("toggle", this, false);
26285 if(this.toggleHandler){
26286 this.toggleHandler.call(this.scope || this, this, state);
26294 focus : function(){
26295 this.el.child('button:first').focus();
26299 * Disable this button
26301 disable : function(){
26303 this.el.addClass("x-btn-disabled");
26305 this.disabled = true;
26309 * Enable this button
26311 enable : function(){
26313 this.el.removeClass("x-btn-disabled");
26315 this.disabled = false;
26319 * Convenience function for boolean enable/disable
26320 * @param {Boolean} enabled True to enable, false to disable
26322 setDisabled : function(v){
26323 this[v !== true ? "enable" : "disable"]();
26327 onClick : function(e){
26329 e.preventDefault();
26334 if(!this.disabled){
26335 if(this.enableToggle){
26338 if(this.menu && !this.menu.isVisible()){
26339 this.menu.show(this.el, this.menuAlign);
26341 this.fireEvent("click", this, e);
26343 this.el.removeClass("x-btn-over");
26344 this.handler.call(this.scope || this, this, e);
26349 onMouseOver : function(e){
26350 if(!this.disabled){
26351 this.el.addClass("x-btn-over");
26352 this.fireEvent('mouseover', this, e);
26356 onMouseOut : function(e){
26357 if(!e.within(this.el, true)){
26358 this.el.removeClass("x-btn-over");
26359 this.fireEvent('mouseout', this, e);
26363 onFocus : function(e){
26364 if(!this.disabled){
26365 this.el.addClass("x-btn-focus");
26369 onBlur : function(e){
26370 this.el.removeClass("x-btn-focus");
26373 onMouseDown : function(e){
26374 if(!this.disabled && e.button == 0){
26375 this.el.addClass("x-btn-click");
26376 Roo.get(document).on('mouseup', this.onMouseUp, this);
26380 onMouseUp : function(e){
26382 this.el.removeClass("x-btn-click");
26383 Roo.get(document).un('mouseup', this.onMouseUp, this);
26387 onMenuShow : function(e){
26388 this.el.addClass("x-btn-menu-active");
26391 onMenuHide : function(e){
26392 this.el.removeClass("x-btn-menu-active");
26396 // Private utility class used by Button
26397 Roo.ButtonToggleMgr = function(){
26400 function toggleGroup(btn, state){
26402 var g = groups[btn.toggleGroup];
26403 for(var i = 0, l = g.length; i < l; i++){
26405 g[i].toggle(false);
26412 register : function(btn){
26413 if(!btn.toggleGroup){
26416 var g = groups[btn.toggleGroup];
26418 g = groups[btn.toggleGroup] = [];
26421 btn.on("toggle", toggleGroup);
26424 unregister : function(btn){
26425 if(!btn.toggleGroup){
26428 var g = groups[btn.toggleGroup];
26431 btn.un("toggle", toggleGroup);
26437 * Ext JS Library 1.1.1
26438 * Copyright(c) 2006-2007, Ext JS, LLC.
26440 * Originally Released Under LGPL - original licence link has changed is not relivant.
26443 * <script type="text/javascript">
26447 * @class Roo.SplitButton
26448 * @extends Roo.Button
26449 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26450 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26451 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26452 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26453 * @cfg {String} arrowTooltip The title attribute of the arrow
26455 * Create a new menu button
26456 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26457 * @param {Object} config The config object
26459 Roo.SplitButton = function(renderTo, config){
26460 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26462 * @event arrowclick
26463 * Fires when this button's arrow is clicked
26464 * @param {SplitButton} this
26465 * @param {EventObject} e The click event
26467 this.addEvents({"arrowclick":true});
26470 Roo.extend(Roo.SplitButton, Roo.Button, {
26471 render : function(renderTo){
26472 // this is one sweet looking template!
26473 var tpl = new Roo.Template(
26474 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26475 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26476 '<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>',
26477 "</tbody></table></td><td>",
26478 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26479 '<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>',
26480 "</tbody></table></td></tr></table>"
26482 var btn = tpl.append(renderTo, [this.text, this.type], true);
26483 var btnEl = btn.child("button");
26485 btn.addClass(this.cls);
26488 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26491 btnEl.addClass(this.iconCls);
26493 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26497 if(this.handleMouseEvents){
26498 btn.on("mouseover", this.onMouseOver, this);
26499 btn.on("mouseout", this.onMouseOut, this);
26500 btn.on("mousedown", this.onMouseDown, this);
26501 btn.on("mouseup", this.onMouseUp, this);
26503 btn.on(this.clickEvent, this.onClick, this);
26505 if(typeof this.tooltip == 'object'){
26506 Roo.QuickTips.tips(Roo.apply({
26510 btnEl.dom[this.tooltipType] = this.tooltip;
26513 if(this.arrowTooltip){
26514 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26523 this.el.addClass("x-btn-pressed");
26525 if(Roo.isIE && !Roo.isIE7){
26526 this.autoWidth.defer(1, this);
26531 this.menu.on("show", this.onMenuShow, this);
26532 this.menu.on("hide", this.onMenuHide, this);
26534 this.fireEvent('render', this);
26538 autoWidth : function(){
26540 var tbl = this.el.child("table:first");
26541 var tbl2 = this.el.child("table:last");
26542 this.el.setWidth("auto");
26543 tbl.setWidth("auto");
26544 if(Roo.isIE7 && Roo.isStrict){
26545 var ib = this.el.child('button:first');
26546 if(ib && ib.getWidth() > 20){
26548 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26553 this.el.beginMeasure();
26555 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26556 tbl.setWidth(this.minWidth-tbl2.getWidth());
26559 this.el.endMeasure();
26562 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26566 * Sets this button's click handler
26567 * @param {Function} handler The function to call when the button is clicked
26568 * @param {Object} scope (optional) Scope for the function passed above
26570 setHandler : function(handler, scope){
26571 this.handler = handler;
26572 this.scope = scope;
26576 * Sets this button's arrow click handler
26577 * @param {Function} handler The function to call when the arrow is clicked
26578 * @param {Object} scope (optional) Scope for the function passed above
26580 setArrowHandler : function(handler, scope){
26581 this.arrowHandler = handler;
26582 this.scope = scope;
26588 focus : function(){
26590 this.el.child("button:first").focus();
26595 onClick : function(e){
26596 e.preventDefault();
26597 if(!this.disabled){
26598 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26599 if(this.menu && !this.menu.isVisible()){
26600 this.menu.show(this.el, this.menuAlign);
26602 this.fireEvent("arrowclick", this, e);
26603 if(this.arrowHandler){
26604 this.arrowHandler.call(this.scope || this, this, e);
26607 this.fireEvent("click", this, e);
26609 this.handler.call(this.scope || this, this, e);
26615 onMouseDown : function(e){
26616 if(!this.disabled){
26617 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26621 onMouseUp : function(e){
26622 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26627 // backwards compat
26628 Roo.MenuButton = Roo.SplitButton;/*
26630 * Ext JS Library 1.1.1
26631 * Copyright(c) 2006-2007, Ext JS, LLC.
26633 * Originally Released Under LGPL - original licence link has changed is not relivant.
26636 * <script type="text/javascript">
26640 * @class Roo.Toolbar
26641 * Basic Toolbar class.
26643 * Creates a new Toolbar
26644 * @param {Object} config The config object
26646 Roo.Toolbar = function(container, buttons, config)
26648 /// old consturctor format still supported..
26649 if(container instanceof Array){ // omit the container for later rendering
26650 buttons = container;
26654 if (typeof(container) == 'object' && container.xtype) {
26655 config = container;
26656 container = config.container;
26657 buttons = config.buttons; // not really - use items!!
26660 if (config && config.items) {
26661 xitems = config.items;
26662 delete config.items;
26664 Roo.apply(this, config);
26665 this.buttons = buttons;
26668 this.render(container);
26670 Roo.each(xitems, function(b) {
26676 Roo.Toolbar.prototype = {
26678 * @cfg {Roo.data.Store} items
26679 * array of button configs or elements to add
26683 * @cfg {String/HTMLElement/Element} container
26684 * The id or element that will contain the toolbar
26687 render : function(ct){
26688 this.el = Roo.get(ct);
26690 this.el.addClass(this.cls);
26692 // using a table allows for vertical alignment
26693 // 100% width is needed by Safari...
26694 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26695 this.tr = this.el.child("tr", true);
26697 this.items = new Roo.util.MixedCollection(false, function(o){
26698 return o.id || ("item" + (++autoId));
26701 this.add.apply(this, this.buttons);
26702 delete this.buttons;
26707 * Adds element(s) to the toolbar -- this function takes a variable number of
26708 * arguments of mixed type and adds them to the toolbar.
26709 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26711 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26712 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26713 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26714 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26715 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26716 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26717 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26718 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26719 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26721 * @param {Mixed} arg2
26722 * @param {Mixed} etc.
26725 var a = arguments, l = a.length;
26726 for(var i = 0; i < l; i++){
26731 _add : function(el) {
26734 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26737 if (el.applyTo){ // some kind of form field
26738 return this.addField(el);
26740 if (el.render){ // some kind of Toolbar.Item
26741 return this.addItem(el);
26743 if (typeof el == "string"){ // string
26744 if(el == "separator" || el == "-"){
26745 return this.addSeparator();
26748 return this.addSpacer();
26751 return this.addFill();
26753 return this.addText(el);
26756 if(el.tagName){ // element
26757 return this.addElement(el);
26759 if(typeof el == "object"){ // must be button config?
26760 return this.addButton(el);
26762 // and now what?!?!
26768 * Add an Xtype element
26769 * @param {Object} xtype Xtype Object
26770 * @return {Object} created Object
26772 addxtype : function(e){
26773 return this.add(e);
26777 * Returns the Element for this toolbar.
26778 * @return {Roo.Element}
26780 getEl : function(){
26786 * @return {Roo.Toolbar.Item} The separator item
26788 addSeparator : function(){
26789 return this.addItem(new Roo.Toolbar.Separator());
26793 * Adds a spacer element
26794 * @return {Roo.Toolbar.Spacer} The spacer item
26796 addSpacer : function(){
26797 return this.addItem(new Roo.Toolbar.Spacer());
26801 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26802 * @return {Roo.Toolbar.Fill} The fill item
26804 addFill : function(){
26805 return this.addItem(new Roo.Toolbar.Fill());
26809 * Adds any standard HTML element to the toolbar
26810 * @param {String/HTMLElement/Element} el The element or id of the element to add
26811 * @return {Roo.Toolbar.Item} The element's item
26813 addElement : function(el){
26814 return this.addItem(new Roo.Toolbar.Item(el));
26817 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26818 * @type Roo.util.MixedCollection
26823 * Adds any Toolbar.Item or subclass
26824 * @param {Roo.Toolbar.Item} item
26825 * @return {Roo.Toolbar.Item} The item
26827 addItem : function(item){
26828 var td = this.nextBlock();
26830 this.items.add(item);
26835 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26836 * @param {Object/Array} config A button config or array of configs
26837 * @return {Roo.Toolbar.Button/Array}
26839 addButton : function(config){
26840 if(config instanceof Array){
26842 for(var i = 0, len = config.length; i < len; i++) {
26843 buttons.push(this.addButton(config[i]));
26848 if(!(config instanceof Roo.Toolbar.Button)){
26850 new Roo.Toolbar.SplitButton(config) :
26851 new Roo.Toolbar.Button(config);
26853 var td = this.nextBlock();
26860 * Adds text to the toolbar
26861 * @param {String} text The text to add
26862 * @return {Roo.Toolbar.Item} The element's item
26864 addText : function(text){
26865 return this.addItem(new Roo.Toolbar.TextItem(text));
26869 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26870 * @param {Number} index The index where the item is to be inserted
26871 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26872 * @return {Roo.Toolbar.Button/Item}
26874 insertButton : function(index, item){
26875 if(item instanceof Array){
26877 for(var i = 0, len = item.length; i < len; i++) {
26878 buttons.push(this.insertButton(index + i, item[i]));
26882 if (!(item instanceof Roo.Toolbar.Button)){
26883 item = new Roo.Toolbar.Button(item);
26885 var td = document.createElement("td");
26886 this.tr.insertBefore(td, this.tr.childNodes[index]);
26888 this.items.insert(index, item);
26893 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26894 * @param {Object} config
26895 * @return {Roo.Toolbar.Item} The element's item
26897 addDom : function(config, returnEl){
26898 var td = this.nextBlock();
26899 Roo.DomHelper.overwrite(td, config);
26900 var ti = new Roo.Toolbar.Item(td.firstChild);
26902 this.items.add(ti);
26907 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26908 * @type Roo.util.MixedCollection
26913 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26914 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26915 * @param {Roo.form.Field} field
26916 * @return {Roo.ToolbarItem}
26920 addField : function(field) {
26921 if (!this.fields) {
26923 this.fields = new Roo.util.MixedCollection(false, function(o){
26924 return o.id || ("item" + (++autoId));
26929 var td = this.nextBlock();
26931 var ti = new Roo.Toolbar.Item(td.firstChild);
26933 this.items.add(ti);
26934 this.fields.add(field);
26945 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26946 this.el.child('div').hide();
26954 this.el.child('div').show();
26958 nextBlock : function(){
26959 var td = document.createElement("td");
26960 this.tr.appendChild(td);
26965 destroy : function(){
26966 if(this.items){ // rendered?
26967 Roo.destroy.apply(Roo, this.items.items);
26969 if(this.fields){ // rendered?
26970 Roo.destroy.apply(Roo, this.fields.items);
26972 Roo.Element.uncache(this.el, this.tr);
26977 * @class Roo.Toolbar.Item
26978 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26980 * Creates a new Item
26981 * @param {HTMLElement} el
26983 Roo.Toolbar.Item = function(el){
26984 this.el = Roo.getDom(el);
26985 this.id = Roo.id(this.el);
26986 this.hidden = false;
26989 Roo.Toolbar.Item.prototype = {
26992 * Get this item's HTML Element
26993 * @return {HTMLElement}
26995 getEl : function(){
27000 render : function(td){
27002 td.appendChild(this.el);
27006 * Removes and destroys this item.
27008 destroy : function(){
27009 this.td.parentNode.removeChild(this.td);
27016 this.hidden = false;
27017 this.td.style.display = "";
27024 this.hidden = true;
27025 this.td.style.display = "none";
27029 * Convenience function for boolean show/hide.
27030 * @param {Boolean} visible true to show/false to hide
27032 setVisible: function(visible){
27041 * Try to focus this item.
27043 focus : function(){
27044 Roo.fly(this.el).focus();
27048 * Disables this item.
27050 disable : function(){
27051 Roo.fly(this.td).addClass("x-item-disabled");
27052 this.disabled = true;
27053 this.el.disabled = true;
27057 * Enables this item.
27059 enable : function(){
27060 Roo.fly(this.td).removeClass("x-item-disabled");
27061 this.disabled = false;
27062 this.el.disabled = false;
27068 * @class Roo.Toolbar.Separator
27069 * @extends Roo.Toolbar.Item
27070 * A simple toolbar separator class
27072 * Creates a new Separator
27074 Roo.Toolbar.Separator = function(){
27075 var s = document.createElement("span");
27076 s.className = "ytb-sep";
27077 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27079 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27080 enable:Roo.emptyFn,
27081 disable:Roo.emptyFn,
27086 * @class Roo.Toolbar.Spacer
27087 * @extends Roo.Toolbar.Item
27088 * A simple element that adds extra horizontal space to a toolbar.
27090 * Creates a new Spacer
27092 Roo.Toolbar.Spacer = function(){
27093 var s = document.createElement("div");
27094 s.className = "ytb-spacer";
27095 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27097 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27098 enable:Roo.emptyFn,
27099 disable:Roo.emptyFn,
27104 * @class Roo.Toolbar.Fill
27105 * @extends Roo.Toolbar.Spacer
27106 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27108 * Creates a new Spacer
27110 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27112 render : function(td){
27113 td.style.width = '100%';
27114 Roo.Toolbar.Fill.superclass.render.call(this, td);
27119 * @class Roo.Toolbar.TextItem
27120 * @extends Roo.Toolbar.Item
27121 * A simple class that renders text directly into a toolbar.
27123 * Creates a new TextItem
27124 * @param {String} text
27126 Roo.Toolbar.TextItem = function(text){
27127 if (typeof(text) == 'object') {
27130 var s = document.createElement("span");
27131 s.className = "ytb-text";
27132 s.innerHTML = text;
27133 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27135 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27136 enable:Roo.emptyFn,
27137 disable:Roo.emptyFn,
27142 * @class Roo.Toolbar.Button
27143 * @extends Roo.Button
27144 * A button that renders into a toolbar.
27146 * Creates a new Button
27147 * @param {Object} config A standard {@link Roo.Button} config object
27149 Roo.Toolbar.Button = function(config){
27150 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27152 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27153 render : function(td){
27155 Roo.Toolbar.Button.superclass.render.call(this, td);
27159 * Removes and destroys this button
27161 destroy : function(){
27162 Roo.Toolbar.Button.superclass.destroy.call(this);
27163 this.td.parentNode.removeChild(this.td);
27167 * Shows this button
27170 this.hidden = false;
27171 this.td.style.display = "";
27175 * Hides this button
27178 this.hidden = true;
27179 this.td.style.display = "none";
27183 * Disables this item
27185 disable : function(){
27186 Roo.fly(this.td).addClass("x-item-disabled");
27187 this.disabled = true;
27191 * Enables this item
27193 enable : function(){
27194 Roo.fly(this.td).removeClass("x-item-disabled");
27195 this.disabled = false;
27198 // backwards compat
27199 Roo.ToolbarButton = Roo.Toolbar.Button;
27202 * @class Roo.Toolbar.SplitButton
27203 * @extends Roo.SplitButton
27204 * A menu button that renders into a toolbar.
27206 * Creates a new SplitButton
27207 * @param {Object} config A standard {@link Roo.SplitButton} config object
27209 Roo.Toolbar.SplitButton = function(config){
27210 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27212 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27213 render : function(td){
27215 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27219 * Removes and destroys this button
27221 destroy : function(){
27222 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27223 this.td.parentNode.removeChild(this.td);
27227 * Shows this button
27230 this.hidden = false;
27231 this.td.style.display = "";
27235 * Hides this button
27238 this.hidden = true;
27239 this.td.style.display = "none";
27243 // backwards compat
27244 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27246 * Ext JS Library 1.1.1
27247 * Copyright(c) 2006-2007, Ext JS, LLC.
27249 * Originally Released Under LGPL - original licence link has changed is not relivant.
27252 * <script type="text/javascript">
27256 * @class Roo.PagingToolbar
27257 * @extends Roo.Toolbar
27258 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27260 * Create a new PagingToolbar
27261 * @param {Object} config The config object
27263 Roo.PagingToolbar = function(el, ds, config)
27265 // old args format still supported... - xtype is prefered..
27266 if (typeof(el) == 'object' && el.xtype) {
27267 // created from xtype...
27269 ds = el.dataSource;
27270 el = config.container;
27273 if (config.items) {
27274 items = config.items;
27278 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27281 this.renderButtons(this.el);
27284 // supprot items array.
27286 Roo.each(items, function(e) {
27287 this.add(Roo.factory(e));
27292 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27294 * @cfg {Roo.data.Store} dataSource
27295 * The underlying data store providing the paged data
27298 * @cfg {String/HTMLElement/Element} container
27299 * container The id or element that will contain the toolbar
27302 * @cfg {Boolean} displayInfo
27303 * True to display the displayMsg (defaults to false)
27306 * @cfg {Number} pageSize
27307 * The number of records to display per page (defaults to 20)
27311 * @cfg {String} displayMsg
27312 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27314 displayMsg : 'Displaying {0} - {1} of {2}',
27316 * @cfg {String} emptyMsg
27317 * The message to display when no records are found (defaults to "No data to display")
27319 emptyMsg : 'No data to display',
27321 * Customizable piece of the default paging text (defaults to "Page")
27324 beforePageText : "Page",
27326 * Customizable piece of the default paging text (defaults to "of %0")
27329 afterPageText : "of {0}",
27331 * Customizable piece of the default paging text (defaults to "First Page")
27334 firstText : "First Page",
27336 * Customizable piece of the default paging text (defaults to "Previous Page")
27339 prevText : "Previous Page",
27341 * Customizable piece of the default paging text (defaults to "Next Page")
27344 nextText : "Next Page",
27346 * Customizable piece of the default paging text (defaults to "Last Page")
27349 lastText : "Last Page",
27351 * Customizable piece of the default paging text (defaults to "Refresh")
27354 refreshText : "Refresh",
27357 renderButtons : function(el){
27358 Roo.PagingToolbar.superclass.render.call(this, el);
27359 this.first = this.addButton({
27360 tooltip: this.firstText,
27361 cls: "x-btn-icon x-grid-page-first",
27363 handler: this.onClick.createDelegate(this, ["first"])
27365 this.prev = this.addButton({
27366 tooltip: this.prevText,
27367 cls: "x-btn-icon x-grid-page-prev",
27369 handler: this.onClick.createDelegate(this, ["prev"])
27371 //this.addSeparator();
27372 this.add(this.beforePageText);
27373 this.field = Roo.get(this.addDom({
27378 cls: "x-grid-page-number"
27380 this.field.on("keydown", this.onPagingKeydown, this);
27381 this.field.on("focus", function(){this.dom.select();});
27382 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27383 this.field.setHeight(18);
27384 //this.addSeparator();
27385 this.next = this.addButton({
27386 tooltip: this.nextText,
27387 cls: "x-btn-icon x-grid-page-next",
27389 handler: this.onClick.createDelegate(this, ["next"])
27391 this.last = this.addButton({
27392 tooltip: this.lastText,
27393 cls: "x-btn-icon x-grid-page-last",
27395 handler: this.onClick.createDelegate(this, ["last"])
27397 //this.addSeparator();
27398 this.loading = this.addButton({
27399 tooltip: this.refreshText,
27400 cls: "x-btn-icon x-grid-loading",
27401 handler: this.onClick.createDelegate(this, ["refresh"])
27404 if(this.displayInfo){
27405 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27410 updateInfo : function(){
27411 if(this.displayEl){
27412 var count = this.ds.getCount();
27413 var msg = count == 0 ?
27417 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27419 this.displayEl.update(msg);
27424 onLoad : function(ds, r, o){
27425 this.cursor = o.params ? o.params.start : 0;
27426 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27428 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27429 this.field.dom.value = ap;
27430 this.first.setDisabled(ap == 1);
27431 this.prev.setDisabled(ap == 1);
27432 this.next.setDisabled(ap == ps);
27433 this.last.setDisabled(ap == ps);
27434 this.loading.enable();
27439 getPageData : function(){
27440 var total = this.ds.getTotalCount();
27443 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27444 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27449 onLoadError : function(){
27450 this.loading.enable();
27454 onPagingKeydown : function(e){
27455 var k = e.getKey();
27456 var d = this.getPageData();
27458 var v = this.field.dom.value, pageNum;
27459 if(!v || isNaN(pageNum = parseInt(v, 10))){
27460 this.field.dom.value = d.activePage;
27463 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27464 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27467 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))
27469 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27470 this.field.dom.value = pageNum;
27471 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27474 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27476 var v = this.field.dom.value, pageNum;
27477 var increment = (e.shiftKey) ? 10 : 1;
27478 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27480 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27481 this.field.dom.value = d.activePage;
27484 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27486 this.field.dom.value = parseInt(v, 10) + increment;
27487 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27488 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27495 beforeLoad : function(){
27497 this.loading.disable();
27502 onClick : function(which){
27506 ds.load({params:{start: 0, limit: this.pageSize}});
27509 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27512 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27515 var total = ds.getTotalCount();
27516 var extra = total % this.pageSize;
27517 var lastStart = extra ? (total - extra) : total-this.pageSize;
27518 ds.load({params:{start: lastStart, limit: this.pageSize}});
27521 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27527 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27528 * @param {Roo.data.Store} store The data store to unbind
27530 unbind : function(ds){
27531 ds.un("beforeload", this.beforeLoad, this);
27532 ds.un("load", this.onLoad, this);
27533 ds.un("loadexception", this.onLoadError, this);
27534 ds.un("remove", this.updateInfo, this);
27535 ds.un("add", this.updateInfo, this);
27536 this.ds = undefined;
27540 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27541 * @param {Roo.data.Store} store The data store to bind
27543 bind : function(ds){
27544 ds.on("beforeload", this.beforeLoad, this);
27545 ds.on("load", this.onLoad, this);
27546 ds.on("loadexception", this.onLoadError, this);
27547 ds.on("remove", this.updateInfo, this);
27548 ds.on("add", this.updateInfo, this);
27553 * Ext JS Library 1.1.1
27554 * Copyright(c) 2006-2007, Ext JS, LLC.
27556 * Originally Released Under LGPL - original licence link has changed is not relivant.
27559 * <script type="text/javascript">
27563 * @class Roo.Resizable
27564 * @extends Roo.util.Observable
27565 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27566 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27567 * 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
27568 * the element will be wrapped for you automatically.</p>
27569 * <p>Here is the list of valid resize handles:</p>
27572 ------ -------------------
27581 'hd' horizontal drag
27584 * <p>Here's an example showing the creation of a typical Resizable:</p>
27586 var resizer = new Roo.Resizable("element-id", {
27594 resizer.on("resize", myHandler);
27596 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27597 * resizer.east.setDisplayed(false);</p>
27598 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27599 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27600 * resize operation's new size (defaults to [0, 0])
27601 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27602 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27603 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27604 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27605 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27606 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27607 * @cfg {Number} width The width of the element in pixels (defaults to null)
27608 * @cfg {Number} height The height of the element in pixels (defaults to null)
27609 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27610 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27611 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27612 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27613 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27614 * in favor of the handles config option (defaults to false)
27615 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27616 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27617 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27618 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27619 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27620 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27621 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27622 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27623 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27624 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27625 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27627 * Create a new resizable component
27628 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27629 * @param {Object} config configuration options
27631 Roo.Resizable = function(el, config)
27633 this.el = Roo.get(el);
27635 if(config && config.wrap){
27636 config.resizeChild = this.el;
27637 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27638 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27639 this.el.setStyle("overflow", "hidden");
27640 this.el.setPositioning(config.resizeChild.getPositioning());
27641 config.resizeChild.clearPositioning();
27642 if(!config.width || !config.height){
27643 var csize = config.resizeChild.getSize();
27644 this.el.setSize(csize.width, csize.height);
27646 if(config.pinned && !config.adjustments){
27647 config.adjustments = "auto";
27651 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27652 this.proxy.unselectable();
27653 this.proxy.enableDisplayMode('block');
27655 Roo.apply(this, config);
27658 this.disableTrackOver = true;
27659 this.el.addClass("x-resizable-pinned");
27661 // if the element isn't positioned, make it relative
27662 var position = this.el.getStyle("position");
27663 if(position != "absolute" && position != "fixed"){
27664 this.el.setStyle("position", "relative");
27666 if(!this.handles){ // no handles passed, must be legacy style
27667 this.handles = 's,e,se';
27668 if(this.multiDirectional){
27669 this.handles += ',n,w';
27672 if(this.handles == "all"){
27673 this.handles = "n s e w ne nw se sw";
27675 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27676 var ps = Roo.Resizable.positions;
27677 for(var i = 0, len = hs.length; i < len; i++){
27678 if(hs[i] && ps[hs[i]]){
27679 var pos = ps[hs[i]];
27680 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27684 this.corner = this.southeast;
27686 // updateBox = the box can move..
27687 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27688 this.updateBox = true;
27691 this.activeHandle = null;
27693 if(this.resizeChild){
27694 if(typeof this.resizeChild == "boolean"){
27695 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27697 this.resizeChild = Roo.get(this.resizeChild, true);
27701 if(this.adjustments == "auto"){
27702 var rc = this.resizeChild;
27703 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27704 if(rc && (hw || hn)){
27705 rc.position("relative");
27706 rc.setLeft(hw ? hw.el.getWidth() : 0);
27707 rc.setTop(hn ? hn.el.getHeight() : 0);
27709 this.adjustments = [
27710 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27711 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27715 if(this.draggable){
27716 this.dd = this.dynamic ?
27717 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27718 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27724 * @event beforeresize
27725 * Fired before resize is allowed. Set enabled to false to cancel resize.
27726 * @param {Roo.Resizable} this
27727 * @param {Roo.EventObject} e The mousedown event
27729 "beforeresize" : true,
27732 * Fired after a resize.
27733 * @param {Roo.Resizable} this
27734 * @param {Number} width The new width
27735 * @param {Number} height The new height
27736 * @param {Roo.EventObject} e The mouseup event
27741 if(this.width !== null && this.height !== null){
27742 this.resizeTo(this.width, this.height);
27744 this.updateChildSize();
27747 this.el.dom.style.zoom = 1;
27749 Roo.Resizable.superclass.constructor.call(this);
27752 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27753 resizeChild : false,
27754 adjustments : [0, 0],
27764 multiDirectional : false,
27765 disableTrackOver : false,
27766 easing : 'easeOutStrong',
27767 widthIncrement : 0,
27768 heightIncrement : 0,
27772 preserveRatio : false,
27773 transparent: false,
27779 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27781 constrainTo: undefined,
27783 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27785 resizeRegion: undefined,
27789 * Perform a manual resize
27790 * @param {Number} width
27791 * @param {Number} height
27793 resizeTo : function(width, height){
27794 this.el.setSize(width, height);
27795 this.updateChildSize();
27796 this.fireEvent("resize", this, width, height, null);
27800 startSizing : function(e, handle){
27801 this.fireEvent("beforeresize", this, e);
27802 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27805 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27806 this.overlay.unselectable();
27807 this.overlay.enableDisplayMode("block");
27808 this.overlay.on("mousemove", this.onMouseMove, this);
27809 this.overlay.on("mouseup", this.onMouseUp, this);
27811 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27813 this.resizing = true;
27814 this.startBox = this.el.getBox();
27815 this.startPoint = e.getXY();
27816 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27817 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27819 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27820 this.overlay.show();
27822 if(this.constrainTo) {
27823 var ct = Roo.get(this.constrainTo);
27824 this.resizeRegion = ct.getRegion().adjust(
27825 ct.getFrameWidth('t'),
27826 ct.getFrameWidth('l'),
27827 -ct.getFrameWidth('b'),
27828 -ct.getFrameWidth('r')
27832 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27834 this.proxy.setBox(this.startBox);
27836 this.proxy.setStyle('visibility', 'visible');
27842 onMouseDown : function(handle, e){
27845 this.activeHandle = handle;
27846 this.startSizing(e, handle);
27851 onMouseUp : function(e){
27852 var size = this.resizeElement();
27853 this.resizing = false;
27855 this.overlay.hide();
27857 this.fireEvent("resize", this, size.width, size.height, e);
27861 updateChildSize : function(){
27862 if(this.resizeChild){
27864 var child = this.resizeChild;
27865 var adj = this.adjustments;
27866 if(el.dom.offsetWidth){
27867 var b = el.getSize(true);
27868 child.setSize(b.width+adj[0], b.height+adj[1]);
27870 // Second call here for IE
27871 // The first call enables instant resizing and
27872 // the second call corrects scroll bars if they
27875 setTimeout(function(){
27876 if(el.dom.offsetWidth){
27877 var b = el.getSize(true);
27878 child.setSize(b.width+adj[0], b.height+adj[1]);
27886 snap : function(value, inc, min){
27887 if(!inc || !value) return value;
27888 var newValue = value;
27889 var m = value % inc;
27892 newValue = value + (inc-m);
27894 newValue = value - m;
27897 return Math.max(min, newValue);
27901 resizeElement : function(){
27902 var box = this.proxy.getBox();
27903 if(this.updateBox){
27904 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27906 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27908 this.updateChildSize();
27916 constrain : function(v, diff, m, mx){
27919 }else if(v - diff > mx){
27926 onMouseMove : function(e){
27928 try{// try catch so if something goes wrong the user doesn't get hung
27930 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27934 //var curXY = this.startPoint;
27935 var curSize = this.curSize || this.startBox;
27936 var x = this.startBox.x, y = this.startBox.y;
27937 var ox = x, oy = y;
27938 var w = curSize.width, h = curSize.height;
27939 var ow = w, oh = h;
27940 var mw = this.minWidth, mh = this.minHeight;
27941 var mxw = this.maxWidth, mxh = this.maxHeight;
27942 var wi = this.widthIncrement;
27943 var hi = this.heightIncrement;
27945 var eventXY = e.getXY();
27946 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27947 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27949 var pos = this.activeHandle.position;
27954 w = Math.min(Math.max(mw, w), mxw);
27959 h = Math.min(Math.max(mh, h), mxh);
27964 w = Math.min(Math.max(mw, w), mxw);
27965 h = Math.min(Math.max(mh, h), mxh);
27968 diffY = this.constrain(h, diffY, mh, mxh);
27975 var adiffX = Math.abs(diffX);
27976 var sub = (adiffX % wi); // how much
27977 if (sub > (wi/2)) { // far enough to snap
27978 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27980 // remove difference..
27981 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27985 x = Math.max(this.minX, x);
27988 diffX = this.constrain(w, diffX, mw, mxw);
27994 w = Math.min(Math.max(mw, w), mxw);
27995 diffY = this.constrain(h, diffY, mh, mxh);
28000 diffX = this.constrain(w, diffX, mw, mxw);
28001 diffY = this.constrain(h, diffY, mh, mxh);
28008 diffX = this.constrain(w, diffX, mw, mxw);
28010 h = Math.min(Math.max(mh, h), mxh);
28016 var sw = this.snap(w, wi, mw);
28017 var sh = this.snap(h, hi, mh);
28018 if(sw != w || sh != h){
28041 if(this.preserveRatio){
28046 h = Math.min(Math.max(mh, h), mxh);
28051 w = Math.min(Math.max(mw, w), mxw);
28056 w = Math.min(Math.max(mw, w), mxw);
28062 w = Math.min(Math.max(mw, w), mxw);
28068 h = Math.min(Math.max(mh, h), mxh);
28076 h = Math.min(Math.max(mh, h), mxh);
28086 h = Math.min(Math.max(mh, h), mxh);
28094 if (pos == 'hdrag') {
28097 this.proxy.setBounds(x, y, w, h);
28099 this.resizeElement();
28106 handleOver : function(){
28108 this.el.addClass("x-resizable-over");
28113 handleOut : function(){
28114 if(!this.resizing){
28115 this.el.removeClass("x-resizable-over");
28120 * Returns the element this component is bound to.
28121 * @return {Roo.Element}
28123 getEl : function(){
28128 * Returns the resizeChild element (or null).
28129 * @return {Roo.Element}
28131 getResizeChild : function(){
28132 return this.resizeChild;
28136 * Destroys this resizable. If the element was wrapped and
28137 * removeEl is not true then the element remains.
28138 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28140 destroy : function(removeEl){
28141 this.proxy.remove();
28143 this.overlay.removeAllListeners();
28144 this.overlay.remove();
28146 var ps = Roo.Resizable.positions;
28148 if(typeof ps[k] != "function" && this[ps[k]]){
28149 var h = this[ps[k]];
28150 h.el.removeAllListeners();
28155 this.el.update("");
28162 // hash to map config positions to true positions
28163 Roo.Resizable.positions = {
28164 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28169 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28171 // only initialize the template if resizable is used
28172 var tpl = Roo.DomHelper.createTemplate(
28173 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28176 Roo.Resizable.Handle.prototype.tpl = tpl;
28178 this.position = pos;
28180 // show north drag fro topdra
28181 var handlepos = pos == 'hdrag' ? 'north' : pos;
28183 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28184 if (pos == 'hdrag') {
28185 this.el.setStyle('cursor', 'pointer');
28187 this.el.unselectable();
28189 this.el.setOpacity(0);
28191 this.el.on("mousedown", this.onMouseDown, this);
28192 if(!disableTrackOver){
28193 this.el.on("mouseover", this.onMouseOver, this);
28194 this.el.on("mouseout", this.onMouseOut, this);
28199 Roo.Resizable.Handle.prototype = {
28200 afterResize : function(rz){
28204 onMouseDown : function(e){
28205 this.rz.onMouseDown(this, e);
28208 onMouseOver : function(e){
28209 this.rz.handleOver(this, e);
28212 onMouseOut : function(e){
28213 this.rz.handleOut(this, e);
28217 * Ext JS Library 1.1.1
28218 * Copyright(c) 2006-2007, Ext JS, LLC.
28220 * Originally Released Under LGPL - original licence link has changed is not relivant.
28223 * <script type="text/javascript">
28227 * @class Roo.Editor
28228 * @extends Roo.Component
28229 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28231 * Create a new Editor
28232 * @param {Roo.form.Field} field The Field object (or descendant)
28233 * @param {Object} config The config object
28235 Roo.Editor = function(field, config){
28236 Roo.Editor.superclass.constructor.call(this, config);
28237 this.field = field;
28240 * @event beforestartedit
28241 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28242 * false from the handler of this event.
28243 * @param {Editor} this
28244 * @param {Roo.Element} boundEl The underlying element bound to this editor
28245 * @param {Mixed} value The field value being set
28247 "beforestartedit" : true,
28250 * Fires when this editor is displayed
28251 * @param {Roo.Element} boundEl The underlying element bound to this editor
28252 * @param {Mixed} value The starting field value
28254 "startedit" : true,
28256 * @event beforecomplete
28257 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28258 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28259 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28260 * event will not fire since no edit actually occurred.
28261 * @param {Editor} this
28262 * @param {Mixed} value The current field value
28263 * @param {Mixed} startValue The original field value
28265 "beforecomplete" : true,
28268 * Fires after editing is complete and any changed value has been written to the underlying field.
28269 * @param {Editor} this
28270 * @param {Mixed} value The current field value
28271 * @param {Mixed} startValue The original field value
28275 * @event specialkey
28276 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28277 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28278 * @param {Roo.form.Field} this
28279 * @param {Roo.EventObject} e The event object
28281 "specialkey" : true
28285 Roo.extend(Roo.Editor, Roo.Component, {
28287 * @cfg {Boolean/String} autosize
28288 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28289 * or "height" to adopt the height only (defaults to false)
28292 * @cfg {Boolean} revertInvalid
28293 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28294 * validation fails (defaults to true)
28297 * @cfg {Boolean} ignoreNoChange
28298 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28299 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28300 * will never be ignored.
28303 * @cfg {Boolean} hideEl
28304 * False to keep the bound element visible while the editor is displayed (defaults to true)
28307 * @cfg {Mixed} value
28308 * The data value of the underlying field (defaults to "")
28312 * @cfg {String} alignment
28313 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28317 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28318 * for bottom-right shadow (defaults to "frame")
28322 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28326 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28328 completeOnEnter : false,
28330 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28332 cancelOnEsc : false,
28334 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28339 onRender : function(ct, position){
28340 this.el = new Roo.Layer({
28341 shadow: this.shadow,
28347 constrain: this.constrain
28349 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28350 if(this.field.msgTarget != 'title'){
28351 this.field.msgTarget = 'qtip';
28353 this.field.render(this.el);
28355 this.field.el.dom.setAttribute('autocomplete', 'off');
28357 this.field.on("specialkey", this.onSpecialKey, this);
28358 if(this.swallowKeys){
28359 this.field.el.swallowEvent(['keydown','keypress']);
28362 this.field.on("blur", this.onBlur, this);
28363 if(this.field.grow){
28364 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28368 onSpecialKey : function(field, e)
28370 //Roo.log('editor onSpecialKey');
28371 if(this.completeOnEnter && e.getKey() == e.ENTER){
28373 this.completeEdit();
28376 // do not fire special key otherwise it might hide close the editor...
28377 if(e.getKey() == e.ENTER){
28380 if(this.cancelOnEsc && e.getKey() == e.ESC){
28384 this.fireEvent('specialkey', field, e);
28389 * Starts the editing process and shows the editor.
28390 * @param {String/HTMLElement/Element} el The element to edit
28391 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28392 * to the innerHTML of el.
28394 startEdit : function(el, value){
28396 this.completeEdit();
28398 this.boundEl = Roo.get(el);
28399 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28400 if(!this.rendered){
28401 this.render(this.parentEl || document.body);
28403 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28406 this.startValue = v;
28407 this.field.setValue(v);
28409 var sz = this.boundEl.getSize();
28410 switch(this.autoSize){
28412 this.setSize(sz.width, "");
28415 this.setSize("", sz.height);
28418 this.setSize(sz.width, sz.height);
28421 this.el.alignTo(this.boundEl, this.alignment);
28422 this.editing = true;
28424 Roo.QuickTips.disable();
28430 * Sets the height and width of this editor.
28431 * @param {Number} width The new width
28432 * @param {Number} height The new height
28434 setSize : function(w, h){
28435 this.field.setSize(w, h);
28442 * Realigns the editor to the bound field based on the current alignment config value.
28444 realign : function(){
28445 this.el.alignTo(this.boundEl, this.alignment);
28449 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28450 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28452 completeEdit : function(remainVisible){
28456 var v = this.getValue();
28457 if(this.revertInvalid !== false && !this.field.isValid()){
28458 v = this.startValue;
28459 this.cancelEdit(true);
28461 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28462 this.editing = false;
28466 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28467 this.editing = false;
28468 if(this.updateEl && this.boundEl){
28469 this.boundEl.update(v);
28471 if(remainVisible !== true){
28474 this.fireEvent("complete", this, v, this.startValue);
28479 onShow : function(){
28481 if(this.hideEl !== false){
28482 this.boundEl.hide();
28485 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28486 this.fixIEFocus = true;
28487 this.deferredFocus.defer(50, this);
28489 this.field.focus();
28491 this.fireEvent("startedit", this.boundEl, this.startValue);
28494 deferredFocus : function(){
28496 this.field.focus();
28501 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28502 * reverted to the original starting value.
28503 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28504 * cancel (defaults to false)
28506 cancelEdit : function(remainVisible){
28508 this.setValue(this.startValue);
28509 if(remainVisible !== true){
28516 onBlur : function(){
28517 if(this.allowBlur !== true && this.editing){
28518 this.completeEdit();
28523 onHide : function(){
28525 this.completeEdit();
28529 if(this.field.collapse){
28530 this.field.collapse();
28533 if(this.hideEl !== false){
28534 this.boundEl.show();
28537 Roo.QuickTips.enable();
28542 * Sets the data value of the editor
28543 * @param {Mixed} value Any valid value supported by the underlying field
28545 setValue : function(v){
28546 this.field.setValue(v);
28550 * Gets the data value of the editor
28551 * @return {Mixed} The data value
28553 getValue : function(){
28554 return this.field.getValue();
28558 * Ext JS Library 1.1.1
28559 * Copyright(c) 2006-2007, Ext JS, LLC.
28561 * Originally Released Under LGPL - original licence link has changed is not relivant.
28564 * <script type="text/javascript">
28568 * @class Roo.BasicDialog
28569 * @extends Roo.util.Observable
28570 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28572 var dlg = new Roo.BasicDialog("my-dlg", {
28581 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28582 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28583 dlg.addButton('Cancel', dlg.hide, dlg);
28586 <b>A Dialog should always be a direct child of the body element.</b>
28587 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28588 * @cfg {String} title Default text to display in the title bar (defaults to null)
28589 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28590 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28591 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28592 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28593 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28594 * (defaults to null with no animation)
28595 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28596 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28597 * property for valid values (defaults to 'all')
28598 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28599 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28600 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28601 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28602 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28603 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28604 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28605 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28606 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28607 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28608 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28609 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28610 * draggable = true (defaults to false)
28611 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28612 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28613 * shadow (defaults to false)
28614 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28615 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28616 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28617 * @cfg {Array} buttons Array of buttons
28618 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28620 * Create a new BasicDialog.
28621 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28622 * @param {Object} config Configuration options
28624 Roo.BasicDialog = function(el, config){
28625 this.el = Roo.get(el);
28626 var dh = Roo.DomHelper;
28627 if(!this.el && config && config.autoCreate){
28628 if(typeof config.autoCreate == "object"){
28629 if(!config.autoCreate.id){
28630 config.autoCreate.id = el;
28632 this.el = dh.append(document.body,
28633 config.autoCreate, true);
28635 this.el = dh.append(document.body,
28636 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28640 el.setDisplayed(true);
28641 el.hide = this.hideAction;
28643 el.addClass("x-dlg");
28645 Roo.apply(this, config);
28647 this.proxy = el.createProxy("x-dlg-proxy");
28648 this.proxy.hide = this.hideAction;
28649 this.proxy.setOpacity(.5);
28653 el.setWidth(config.width);
28656 el.setHeight(config.height);
28658 this.size = el.getSize();
28659 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28660 this.xy = [config.x,config.y];
28662 this.xy = el.getCenterXY(true);
28664 /** The header element @type Roo.Element */
28665 this.header = el.child("> .x-dlg-hd");
28666 /** The body element @type Roo.Element */
28667 this.body = el.child("> .x-dlg-bd");
28668 /** The footer element @type Roo.Element */
28669 this.footer = el.child("> .x-dlg-ft");
28672 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28675 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28678 this.header.unselectable();
28680 this.header.update(this.title);
28682 // this element allows the dialog to be focused for keyboard event
28683 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28684 this.focusEl.swallowEvent("click", true);
28686 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28688 // wrap the body and footer for special rendering
28689 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28691 this.bwrap.dom.appendChild(this.footer.dom);
28694 this.bg = this.el.createChild({
28695 tag: "div", cls:"x-dlg-bg",
28696 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28698 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28701 if(this.autoScroll !== false && !this.autoTabs){
28702 this.body.setStyle("overflow", "auto");
28705 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28707 if(this.closable !== false){
28708 this.el.addClass("x-dlg-closable");
28709 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28710 this.close.on("click", this.closeClick, this);
28711 this.close.addClassOnOver("x-dlg-close-over");
28713 if(this.collapsible !== false){
28714 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28715 this.collapseBtn.on("click", this.collapseClick, this);
28716 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28717 this.header.on("dblclick", this.collapseClick, this);
28719 if(this.resizable !== false){
28720 this.el.addClass("x-dlg-resizable");
28721 this.resizer = new Roo.Resizable(el, {
28722 minWidth: this.minWidth || 80,
28723 minHeight:this.minHeight || 80,
28724 handles: this.resizeHandles || "all",
28727 this.resizer.on("beforeresize", this.beforeResize, this);
28728 this.resizer.on("resize", this.onResize, this);
28730 if(this.draggable !== false){
28731 el.addClass("x-dlg-draggable");
28732 if (!this.proxyDrag) {
28733 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28736 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28738 dd.setHandleElId(this.header.id);
28739 dd.endDrag = this.endMove.createDelegate(this);
28740 dd.startDrag = this.startMove.createDelegate(this);
28741 dd.onDrag = this.onDrag.createDelegate(this);
28746 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28747 this.mask.enableDisplayMode("block");
28749 this.el.addClass("x-dlg-modal");
28752 this.shadow = new Roo.Shadow({
28753 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28754 offset : this.shadowOffset
28757 this.shadowOffset = 0;
28759 if(Roo.useShims && this.shim !== false){
28760 this.shim = this.el.createShim();
28761 this.shim.hide = this.hideAction;
28769 if (this.buttons) {
28770 var bts= this.buttons;
28772 Roo.each(bts, function(b) {
28781 * Fires when a key is pressed
28782 * @param {Roo.BasicDialog} this
28783 * @param {Roo.EventObject} e
28788 * Fires when this dialog is moved by the user.
28789 * @param {Roo.BasicDialog} this
28790 * @param {Number} x The new page X
28791 * @param {Number} y The new page Y
28796 * Fires when this dialog is resized by the user.
28797 * @param {Roo.BasicDialog} this
28798 * @param {Number} width The new width
28799 * @param {Number} height The new height
28803 * @event beforehide
28804 * Fires before this dialog is hidden.
28805 * @param {Roo.BasicDialog} this
28807 "beforehide" : true,
28810 * Fires when this dialog is hidden.
28811 * @param {Roo.BasicDialog} this
28815 * @event beforeshow
28816 * Fires before this dialog is shown.
28817 * @param {Roo.BasicDialog} this
28819 "beforeshow" : true,
28822 * Fires when this dialog is shown.
28823 * @param {Roo.BasicDialog} this
28827 el.on("keydown", this.onKeyDown, this);
28828 el.on("mousedown", this.toFront, this);
28829 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28831 Roo.DialogManager.register(this);
28832 Roo.BasicDialog.superclass.constructor.call(this);
28835 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28836 shadowOffset: Roo.isIE ? 6 : 5,
28839 minButtonWidth: 75,
28840 defaultButton: null,
28841 buttonAlign: "right",
28846 * Sets the dialog title text
28847 * @param {String} text The title text to display
28848 * @return {Roo.BasicDialog} this
28850 setTitle : function(text){
28851 this.header.update(text);
28856 closeClick : function(){
28861 collapseClick : function(){
28862 this[this.collapsed ? "expand" : "collapse"]();
28866 * Collapses the dialog to its minimized state (only the title bar is visible).
28867 * Equivalent to the user clicking the collapse dialog button.
28869 collapse : function(){
28870 if(!this.collapsed){
28871 this.collapsed = true;
28872 this.el.addClass("x-dlg-collapsed");
28873 this.restoreHeight = this.el.getHeight();
28874 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28879 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28880 * clicking the expand dialog button.
28882 expand : function(){
28883 if(this.collapsed){
28884 this.collapsed = false;
28885 this.el.removeClass("x-dlg-collapsed");
28886 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28891 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28892 * @return {Roo.TabPanel} The tabs component
28894 initTabs : function(){
28895 var tabs = this.getTabs();
28896 while(tabs.getTab(0)){
28899 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28901 tabs.addTab(Roo.id(dom), dom.title);
28909 beforeResize : function(){
28910 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28914 onResize : function(){
28915 this.refreshSize();
28916 this.syncBodyHeight();
28917 this.adjustAssets();
28919 this.fireEvent("resize", this, this.size.width, this.size.height);
28923 onKeyDown : function(e){
28924 if(this.isVisible()){
28925 this.fireEvent("keydown", this, e);
28930 * Resizes the dialog.
28931 * @param {Number} width
28932 * @param {Number} height
28933 * @return {Roo.BasicDialog} this
28935 resizeTo : function(width, height){
28936 this.el.setSize(width, height);
28937 this.size = {width: width, height: height};
28938 this.syncBodyHeight();
28939 if(this.fixedcenter){
28942 if(this.isVisible()){
28943 this.constrainXY();
28944 this.adjustAssets();
28946 this.fireEvent("resize", this, width, height);
28952 * Resizes the dialog to fit the specified content size.
28953 * @param {Number} width
28954 * @param {Number} height
28955 * @return {Roo.BasicDialog} this
28957 setContentSize : function(w, h){
28958 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28959 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28960 //if(!this.el.isBorderBox()){
28961 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28962 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28965 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28966 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28968 this.resizeTo(w, h);
28973 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28974 * executed in response to a particular key being pressed while the dialog is active.
28975 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28976 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28977 * @param {Function} fn The function to call
28978 * @param {Object} scope (optional) The scope of the function
28979 * @return {Roo.BasicDialog} this
28981 addKeyListener : function(key, fn, scope){
28982 var keyCode, shift, ctrl, alt;
28983 if(typeof key == "object" && !(key instanceof Array)){
28984 keyCode = key["key"];
28985 shift = key["shift"];
28986 ctrl = key["ctrl"];
28991 var handler = function(dlg, e){
28992 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28993 var k = e.getKey();
28994 if(keyCode instanceof Array){
28995 for(var i = 0, len = keyCode.length; i < len; i++){
28996 if(keyCode[i] == k){
28997 fn.call(scope || window, dlg, k, e);
29003 fn.call(scope || window, dlg, k, e);
29008 this.on("keydown", handler);
29013 * Returns the TabPanel component (creates it if it doesn't exist).
29014 * Note: If you wish to simply check for the existence of tabs without creating them,
29015 * check for a null 'tabs' property.
29016 * @return {Roo.TabPanel} The tabs component
29018 getTabs : function(){
29020 this.el.addClass("x-dlg-auto-tabs");
29021 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29022 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29028 * Adds a button to the footer section of the dialog.
29029 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29030 * object or a valid Roo.DomHelper element config
29031 * @param {Function} handler The function called when the button is clicked
29032 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29033 * @return {Roo.Button} The new button
29035 addButton : function(config, handler, scope){
29036 var dh = Roo.DomHelper;
29038 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29040 if(!this.btnContainer){
29041 var tb = this.footer.createChild({
29043 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29044 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29046 this.btnContainer = tb.firstChild.firstChild.firstChild;
29051 minWidth: this.minButtonWidth,
29054 if(typeof config == "string"){
29055 bconfig.text = config;
29058 bconfig.dhconfig = config;
29060 Roo.apply(bconfig, config);
29064 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29065 bconfig.position = Math.max(0, bconfig.position);
29066 fc = this.btnContainer.childNodes[bconfig.position];
29069 var btn = new Roo.Button(
29071 this.btnContainer.insertBefore(document.createElement("td"),fc)
29072 : this.btnContainer.appendChild(document.createElement("td")),
29073 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29076 this.syncBodyHeight();
29079 * Array of all the buttons that have been added to this dialog via addButton
29084 this.buttons.push(btn);
29089 * Sets the default button to be focused when the dialog is displayed.
29090 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29091 * @return {Roo.BasicDialog} this
29093 setDefaultButton : function(btn){
29094 this.defaultButton = btn;
29099 getHeaderFooterHeight : function(safe){
29102 height += this.header.getHeight();
29105 var fm = this.footer.getMargins();
29106 height += (this.footer.getHeight()+fm.top+fm.bottom);
29108 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29109 height += this.centerBg.getPadding("tb");
29114 syncBodyHeight : function(){
29115 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29116 var height = this.size.height - this.getHeaderFooterHeight(false);
29117 bd.setHeight(height-bd.getMargins("tb"));
29118 var hh = this.header.getHeight();
29119 var h = this.size.height-hh;
29121 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29122 bw.setHeight(h-cb.getPadding("tb"));
29123 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29124 bd.setWidth(bw.getWidth(true));
29126 this.tabs.syncHeight();
29128 this.tabs.el.repaint();
29134 * Restores the previous state of the dialog if Roo.state is configured.
29135 * @return {Roo.BasicDialog} this
29137 restoreState : function(){
29138 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29139 if(box && box.width){
29140 this.xy = [box.x, box.y];
29141 this.resizeTo(box.width, box.height);
29147 beforeShow : function(){
29149 if(this.fixedcenter){
29150 this.xy = this.el.getCenterXY(true);
29153 Roo.get(document.body).addClass("x-body-masked");
29154 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29157 this.constrainXY();
29161 animShow : function(){
29162 var b = Roo.get(this.animateTarget).getBox();
29163 this.proxy.setSize(b.width, b.height);
29164 this.proxy.setLocation(b.x, b.y);
29166 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29167 true, .35, this.showEl.createDelegate(this));
29171 * Shows the dialog.
29172 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29173 * @return {Roo.BasicDialog} this
29175 show : function(animateTarget){
29176 if (this.fireEvent("beforeshow", this) === false){
29179 if(this.syncHeightBeforeShow){
29180 this.syncBodyHeight();
29181 }else if(this.firstShow){
29182 this.firstShow = false;
29183 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29185 this.animateTarget = animateTarget || this.animateTarget;
29186 if(!this.el.isVisible()){
29188 if(this.animateTarget && Roo.get(this.animateTarget)){
29198 showEl : function(){
29200 this.el.setXY(this.xy);
29202 this.adjustAssets(true);
29205 // IE peekaboo bug - fix found by Dave Fenwick
29209 this.fireEvent("show", this);
29213 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29214 * dialog itself will receive focus.
29216 focus : function(){
29217 if(this.defaultButton){
29218 this.defaultButton.focus();
29220 this.focusEl.focus();
29225 constrainXY : function(){
29226 if(this.constraintoviewport !== false){
29227 if(!this.viewSize){
29228 if(this.container){
29229 var s = this.container.getSize();
29230 this.viewSize = [s.width, s.height];
29232 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29235 var s = Roo.get(this.container||document).getScroll();
29237 var x = this.xy[0], y = this.xy[1];
29238 var w = this.size.width, h = this.size.height;
29239 var vw = this.viewSize[0], vh = this.viewSize[1];
29240 // only move it if it needs it
29242 // first validate right/bottom
29243 if(x + w > vw+s.left){
29247 if(y + h > vh+s.top){
29251 // then make sure top/left isn't negative
29263 if(this.isVisible()){
29264 this.el.setLocation(x, y);
29265 this.adjustAssets();
29272 onDrag : function(){
29273 if(!this.proxyDrag){
29274 this.xy = this.el.getXY();
29275 this.adjustAssets();
29280 adjustAssets : function(doShow){
29281 var x = this.xy[0], y = this.xy[1];
29282 var w = this.size.width, h = this.size.height;
29283 if(doShow === true){
29285 this.shadow.show(this.el);
29291 if(this.shadow && this.shadow.isVisible()){
29292 this.shadow.show(this.el);
29294 if(this.shim && this.shim.isVisible()){
29295 this.shim.setBounds(x, y, w, h);
29300 adjustViewport : function(w, h){
29302 w = Roo.lib.Dom.getViewWidth();
29303 h = Roo.lib.Dom.getViewHeight();
29306 this.viewSize = [w, h];
29307 if(this.modal && this.mask.isVisible()){
29308 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29309 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29311 if(this.isVisible()){
29312 this.constrainXY();
29317 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29318 * shadow, proxy, mask, etc.) Also removes all event listeners.
29319 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29321 destroy : function(removeEl){
29322 if(this.isVisible()){
29323 this.animateTarget = null;
29326 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29328 this.tabs.destroy(removeEl);
29341 for(var i = 0, len = this.buttons.length; i < len; i++){
29342 this.buttons[i].destroy();
29345 this.el.removeAllListeners();
29346 if(removeEl === true){
29347 this.el.update("");
29350 Roo.DialogManager.unregister(this);
29354 startMove : function(){
29355 if(this.proxyDrag){
29358 if(this.constraintoviewport !== false){
29359 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29364 endMove : function(){
29365 if(!this.proxyDrag){
29366 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29368 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29371 this.refreshSize();
29372 this.adjustAssets();
29374 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29378 * Brings this dialog to the front of any other visible dialogs
29379 * @return {Roo.BasicDialog} this
29381 toFront : function(){
29382 Roo.DialogManager.bringToFront(this);
29387 * Sends this dialog to the back (under) of any other visible dialogs
29388 * @return {Roo.BasicDialog} this
29390 toBack : function(){
29391 Roo.DialogManager.sendToBack(this);
29396 * Centers this dialog in the viewport
29397 * @return {Roo.BasicDialog} this
29399 center : function(){
29400 var xy = this.el.getCenterXY(true);
29401 this.moveTo(xy[0], xy[1]);
29406 * Moves the dialog's top-left corner to the specified point
29407 * @param {Number} x
29408 * @param {Number} y
29409 * @return {Roo.BasicDialog} this
29411 moveTo : function(x, y){
29413 if(this.isVisible()){
29414 this.el.setXY(this.xy);
29415 this.adjustAssets();
29421 * Aligns the dialog to the specified element
29422 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29423 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29424 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29425 * @return {Roo.BasicDialog} this
29427 alignTo : function(element, position, offsets){
29428 this.xy = this.el.getAlignToXY(element, position, offsets);
29429 if(this.isVisible()){
29430 this.el.setXY(this.xy);
29431 this.adjustAssets();
29437 * Anchors an element to another element and realigns it when the window is resized.
29438 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29439 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29440 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29441 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29442 * is a number, it is used as the buffer delay (defaults to 50ms).
29443 * @return {Roo.BasicDialog} this
29445 anchorTo : function(el, alignment, offsets, monitorScroll){
29446 var action = function(){
29447 this.alignTo(el, alignment, offsets);
29449 Roo.EventManager.onWindowResize(action, this);
29450 var tm = typeof monitorScroll;
29451 if(tm != 'undefined'){
29452 Roo.EventManager.on(window, 'scroll', action, this,
29453 {buffer: tm == 'number' ? monitorScroll : 50});
29460 * Returns true if the dialog is visible
29461 * @return {Boolean}
29463 isVisible : function(){
29464 return this.el.isVisible();
29468 animHide : function(callback){
29469 var b = Roo.get(this.animateTarget).getBox();
29471 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29473 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29474 this.hideEl.createDelegate(this, [callback]));
29478 * Hides the dialog.
29479 * @param {Function} callback (optional) Function to call when the dialog is hidden
29480 * @return {Roo.BasicDialog} this
29482 hide : function(callback){
29483 if (this.fireEvent("beforehide", this) === false){
29487 this.shadow.hide();
29492 // sometimes animateTarget seems to get set.. causing problems...
29493 // this just double checks..
29494 if(this.animateTarget && Roo.get(this.animateTarget)) {
29495 this.animHide(callback);
29498 this.hideEl(callback);
29504 hideEl : function(callback){
29508 Roo.get(document.body).removeClass("x-body-masked");
29510 this.fireEvent("hide", this);
29511 if(typeof callback == "function"){
29517 hideAction : function(){
29518 this.setLeft("-10000px");
29519 this.setTop("-10000px");
29520 this.setStyle("visibility", "hidden");
29524 refreshSize : function(){
29525 this.size = this.el.getSize();
29526 this.xy = this.el.getXY();
29527 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29531 // z-index is managed by the DialogManager and may be overwritten at any time
29532 setZIndex : function(index){
29534 this.mask.setStyle("z-index", index);
29537 this.shim.setStyle("z-index", ++index);
29540 this.shadow.setZIndex(++index);
29542 this.el.setStyle("z-index", ++index);
29544 this.proxy.setStyle("z-index", ++index);
29547 this.resizer.proxy.setStyle("z-index", ++index);
29550 this.lastZIndex = index;
29554 * Returns the element for this dialog
29555 * @return {Roo.Element} The underlying dialog Element
29557 getEl : function(){
29563 * @class Roo.DialogManager
29564 * Provides global access to BasicDialogs that have been created and
29565 * support for z-indexing (layering) multiple open dialogs.
29567 Roo.DialogManager = function(){
29569 var accessList = [];
29573 var sortDialogs = function(d1, d2){
29574 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29578 var orderDialogs = function(){
29579 accessList.sort(sortDialogs);
29580 var seed = Roo.DialogManager.zseed;
29581 for(var i = 0, len = accessList.length; i < len; i++){
29582 var dlg = accessList[i];
29584 dlg.setZIndex(seed + (i*10));
29591 * The starting z-index for BasicDialogs (defaults to 9000)
29592 * @type Number The z-index value
29597 register : function(dlg){
29598 list[dlg.id] = dlg;
29599 accessList.push(dlg);
29603 unregister : function(dlg){
29604 delete list[dlg.id];
29607 if(!accessList.indexOf){
29608 for( i = 0, len = accessList.length; i < len; i++){
29609 if(accessList[i] == dlg){
29610 accessList.splice(i, 1);
29615 i = accessList.indexOf(dlg);
29617 accessList.splice(i, 1);
29623 * Gets a registered dialog by id
29624 * @param {String/Object} id The id of the dialog or a dialog
29625 * @return {Roo.BasicDialog} this
29627 get : function(id){
29628 return typeof id == "object" ? id : list[id];
29632 * Brings the specified dialog to the front
29633 * @param {String/Object} dlg The id of the dialog or a dialog
29634 * @return {Roo.BasicDialog} this
29636 bringToFront : function(dlg){
29637 dlg = this.get(dlg);
29640 dlg._lastAccess = new Date().getTime();
29647 * Sends the specified dialog to the back
29648 * @param {String/Object} dlg The id of the dialog or a dialog
29649 * @return {Roo.BasicDialog} this
29651 sendToBack : function(dlg){
29652 dlg = this.get(dlg);
29653 dlg._lastAccess = -(new Date().getTime());
29659 * Hides all dialogs
29661 hideAll : function(){
29662 for(var id in list){
29663 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29672 * @class Roo.LayoutDialog
29673 * @extends Roo.BasicDialog
29674 * Dialog which provides adjustments for working with a layout in a Dialog.
29675 * Add your necessary layout config options to the dialog's config.<br>
29676 * Example usage (including a nested layout):
29679 dialog = new Roo.LayoutDialog("download-dlg", {
29688 // layout config merges with the dialog config
29690 tabPosition: "top",
29691 alwaysShowTabs: true
29694 dialog.addKeyListener(27, dialog.hide, dialog);
29695 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29696 dialog.addButton("Build It!", this.getDownload, this);
29698 // we can even add nested layouts
29699 var innerLayout = new Roo.BorderLayout("dl-inner", {
29709 innerLayout.beginUpdate();
29710 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29711 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29712 innerLayout.endUpdate(true);
29714 var layout = dialog.getLayout();
29715 layout.beginUpdate();
29716 layout.add("center", new Roo.ContentPanel("standard-panel",
29717 {title: "Download the Source", fitToFrame:true}));
29718 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29719 {title: "Build your own roo.js"}));
29720 layout.getRegion("center").showPanel(sp);
29721 layout.endUpdate();
29725 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29726 * @param {Object} config configuration options
29728 Roo.LayoutDialog = function(el, cfg){
29731 if (typeof(cfg) == 'undefined') {
29732 config = Roo.apply({}, el);
29733 // not sure why we use documentElement here.. - it should always be body.
29734 // IE7 borks horribly if we use documentElement.
29735 // webkit also does not like documentElement - it creates a body element...
29736 el = Roo.get( document.body || document.documentElement ).createChild();
29737 //config.autoCreate = true;
29741 config.autoTabs = false;
29742 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29743 this.body.setStyle({overflow:"hidden", position:"relative"});
29744 this.layout = new Roo.BorderLayout(this.body.dom, config);
29745 this.layout.monitorWindowResize = false;
29746 this.el.addClass("x-dlg-auto-layout");
29747 // fix case when center region overwrites center function
29748 this.center = Roo.BasicDialog.prototype.center;
29749 this.on("show", this.layout.layout, this.layout, true);
29750 if (config.items) {
29751 var xitems = config.items;
29752 delete config.items;
29753 Roo.each(xitems, this.addxtype, this);
29758 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29760 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29763 endUpdate : function(){
29764 this.layout.endUpdate();
29768 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29771 beginUpdate : function(){
29772 this.layout.beginUpdate();
29776 * Get the BorderLayout for this dialog
29777 * @return {Roo.BorderLayout}
29779 getLayout : function(){
29780 return this.layout;
29783 showEl : function(){
29784 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29786 this.layout.layout();
29791 // Use the syncHeightBeforeShow config option to control this automatically
29792 syncBodyHeight : function(){
29793 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29794 if(this.layout){this.layout.layout();}
29798 * Add an xtype element (actually adds to the layout.)
29799 * @return {Object} xdata xtype object data.
29802 addxtype : function(c) {
29803 return this.layout.addxtype(c);
29807 * Ext JS Library 1.1.1
29808 * Copyright(c) 2006-2007, Ext JS, LLC.
29810 * Originally Released Under LGPL - original licence link has changed is not relivant.
29813 * <script type="text/javascript">
29817 * @class Roo.MessageBox
29818 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29822 Roo.Msg.alert('Status', 'Changes saved successfully.');
29824 // Prompt for user data:
29825 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29827 // process text value...
29831 // Show a dialog using config options:
29833 title:'Save Changes?',
29834 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29835 buttons: Roo.Msg.YESNOCANCEL,
29842 Roo.MessageBox = function(){
29843 var dlg, opt, mask, waitTimer;
29844 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29845 var buttons, activeTextEl, bwidth;
29848 var handleButton = function(button){
29850 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29854 var handleHide = function(){
29855 if(opt && opt.cls){
29856 dlg.el.removeClass(opt.cls);
29859 Roo.TaskMgr.stop(waitTimer);
29865 var updateButtons = function(b){
29868 buttons["ok"].hide();
29869 buttons["cancel"].hide();
29870 buttons["yes"].hide();
29871 buttons["no"].hide();
29872 dlg.footer.dom.style.display = 'none';
29875 dlg.footer.dom.style.display = '';
29876 for(var k in buttons){
29877 if(typeof buttons[k] != "function"){
29880 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29881 width += buttons[k].el.getWidth()+15;
29891 var handleEsc = function(d, k, e){
29892 if(opt && opt.closable !== false){
29902 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29903 * @return {Roo.BasicDialog} The BasicDialog element
29905 getDialog : function(){
29907 dlg = new Roo.BasicDialog("x-msg-box", {
29912 constraintoviewport:false,
29914 collapsible : false,
29917 width:400, height:100,
29918 buttonAlign:"center",
29919 closeClick : function(){
29920 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29921 handleButton("no");
29923 handleButton("cancel");
29927 dlg.on("hide", handleHide);
29929 dlg.addKeyListener(27, handleEsc);
29931 var bt = this.buttonText;
29932 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29933 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29934 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29935 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29936 bodyEl = dlg.body.createChild({
29938 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>'
29940 msgEl = bodyEl.dom.firstChild;
29941 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29942 textboxEl.enableDisplayMode();
29943 textboxEl.addKeyListener([10,13], function(){
29944 if(dlg.isVisible() && opt && opt.buttons){
29945 if(opt.buttons.ok){
29946 handleButton("ok");
29947 }else if(opt.buttons.yes){
29948 handleButton("yes");
29952 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29953 textareaEl.enableDisplayMode();
29954 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29955 progressEl.enableDisplayMode();
29956 var pf = progressEl.dom.firstChild;
29958 pp = Roo.get(pf.firstChild);
29959 pp.setHeight(pf.offsetHeight);
29967 * Updates the message box body text
29968 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29969 * the XHTML-compliant non-breaking space character '&#160;')
29970 * @return {Roo.MessageBox} This message box
29972 updateText : function(text){
29973 if(!dlg.isVisible() && !opt.width){
29974 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29976 msgEl.innerHTML = text || ' ';
29977 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29978 Math.max(opt.minWidth || this.minWidth, bwidth));
29980 activeTextEl.setWidth(w);
29982 if(dlg.isVisible()){
29983 dlg.fixedcenter = false;
29985 dlg.setContentSize(w, bodyEl.getHeight());
29986 if(dlg.isVisible()){
29987 dlg.fixedcenter = true;
29993 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29994 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29995 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29996 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29997 * @return {Roo.MessageBox} This message box
29999 updateProgress : function(value, text){
30001 this.updateText(text);
30003 if (pp) { // weird bug on my firefox - for some reason this is not defined
30004 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30010 * Returns true if the message box is currently displayed
30011 * @return {Boolean} True if the message box is visible, else false
30013 isVisible : function(){
30014 return dlg && dlg.isVisible();
30018 * Hides the message box if it is displayed
30021 if(this.isVisible()){
30027 * Displays a new message box, or reinitializes an existing message box, based on the config options
30028 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30029 * The following config object properties are supported:
30031 Property Type Description
30032 ---------- --------------- ------------------------------------------------------------------------------------
30033 animEl String/Element An id or Element from which the message box should animate as it opens and
30034 closes (defaults to undefined)
30035 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30036 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30037 closable Boolean False to hide the top-right close button (defaults to true). Note that
30038 progress and wait dialogs will ignore this property and always hide the
30039 close button as they can only be closed programmatically.
30040 cls String A custom CSS class to apply to the message box element
30041 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30042 displayed (defaults to 75)
30043 fn Function A callback function to execute after closing the dialog. The arguments to the
30044 function will be btn (the name of the button that was clicked, if applicable,
30045 e.g. "ok"), and text (the value of the active text field, if applicable).
30046 Progress and wait dialogs will ignore this option since they do not respond to
30047 user actions and can only be closed programmatically, so any required function
30048 should be called by the same code after it closes the dialog.
30049 icon String A CSS class that provides a background image to be used as an icon for
30050 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30051 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30052 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30053 modal Boolean False to allow user interaction with the page while the message box is
30054 displayed (defaults to true)
30055 msg String A string that will replace the existing message box body text (defaults
30056 to the XHTML-compliant non-breaking space character ' ')
30057 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30058 progress Boolean True to display a progress bar (defaults to false)
30059 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30060 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30061 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30062 title String The title text
30063 value String The string value to set into the active textbox element if displayed
30064 wait Boolean True to display a progress bar (defaults to false)
30065 width Number The width of the dialog in pixels
30072 msg: 'Please enter your address:',
30074 buttons: Roo.MessageBox.OKCANCEL,
30077 animEl: 'addAddressBtn'
30080 * @param {Object} config Configuration options
30081 * @return {Roo.MessageBox} This message box
30083 show : function(options){
30084 if(this.isVisible()){
30087 var d = this.getDialog();
30089 d.setTitle(opt.title || " ");
30090 d.close.setDisplayed(opt.closable !== false);
30091 activeTextEl = textboxEl;
30092 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30097 textareaEl.setHeight(typeof opt.multiline == "number" ?
30098 opt.multiline : this.defaultTextHeight);
30099 activeTextEl = textareaEl;
30108 progressEl.setDisplayed(opt.progress === true);
30109 this.updateProgress(0);
30110 activeTextEl.dom.value = opt.value || "";
30112 dlg.setDefaultButton(activeTextEl);
30114 var bs = opt.buttons;
30117 db = buttons["ok"];
30118 }else if(bs && bs.yes){
30119 db = buttons["yes"];
30121 dlg.setDefaultButton(db);
30123 bwidth = updateButtons(opt.buttons);
30124 this.updateText(opt.msg);
30126 d.el.addClass(opt.cls);
30128 d.proxyDrag = opt.proxyDrag === true;
30129 d.modal = opt.modal !== false;
30130 d.mask = opt.modal !== false ? mask : false;
30131 if(!d.isVisible()){
30132 // force it to the end of the z-index stack so it gets a cursor in FF
30133 document.body.appendChild(dlg.el.dom);
30134 d.animateTarget = null;
30135 d.show(options.animEl);
30141 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30142 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30143 * and closing the message box when the process is complete.
30144 * @param {String} title The title bar text
30145 * @param {String} msg The message box body text
30146 * @return {Roo.MessageBox} This message box
30148 progress : function(title, msg){
30155 minWidth: this.minProgressWidth,
30162 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30163 * If a callback function is passed it will be called after the user clicks the button, and the
30164 * id of the button that was clicked will be passed as the only parameter to the callback
30165 * (could also be the top-right close button).
30166 * @param {String} title The title bar text
30167 * @param {String} msg The message box body text
30168 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30169 * @param {Object} scope (optional) The scope of the callback function
30170 * @return {Roo.MessageBox} This message box
30172 alert : function(title, msg, fn, scope){
30185 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30186 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30187 * You are responsible for closing the message box when the process is complete.
30188 * @param {String} msg The message box body text
30189 * @param {String} title (optional) The title bar text
30190 * @return {Roo.MessageBox} This message box
30192 wait : function(msg, title){
30203 waitTimer = Roo.TaskMgr.start({
30205 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30213 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30214 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30215 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30216 * @param {String} title The title bar text
30217 * @param {String} msg The message box body text
30218 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30219 * @param {Object} scope (optional) The scope of the callback function
30220 * @return {Roo.MessageBox} This message box
30222 confirm : function(title, msg, fn, scope){
30226 buttons: this.YESNO,
30235 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30236 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30237 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30238 * (could also be the top-right close button) and the text that was entered will be passed as the two
30239 * parameters to the callback.
30240 * @param {String} title The title bar text
30241 * @param {String} msg The message box body text
30242 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30243 * @param {Object} scope (optional) The scope of the callback function
30244 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30245 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30246 * @return {Roo.MessageBox} This message box
30248 prompt : function(title, msg, fn, scope, multiline){
30252 buttons: this.OKCANCEL,
30257 multiline: multiline,
30264 * Button config that displays a single OK button
30269 * Button config that displays Yes and No buttons
30272 YESNO : {yes:true, no:true},
30274 * Button config that displays OK and Cancel buttons
30277 OKCANCEL : {ok:true, cancel:true},
30279 * Button config that displays Yes, No and Cancel buttons
30282 YESNOCANCEL : {yes:true, no:true, cancel:true},
30285 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30288 defaultTextHeight : 75,
30290 * The maximum width in pixels of the message box (defaults to 600)
30295 * The minimum width in pixels of the message box (defaults to 100)
30300 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30301 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30304 minProgressWidth : 250,
30306 * An object containing the default button text strings that can be overriden for localized language support.
30307 * Supported properties are: ok, cancel, yes and no.
30308 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30321 * Shorthand for {@link Roo.MessageBox}
30323 Roo.Msg = Roo.MessageBox;/*
30325 * Ext JS Library 1.1.1
30326 * Copyright(c) 2006-2007, Ext JS, LLC.
30328 * Originally Released Under LGPL - original licence link has changed is not relivant.
30331 * <script type="text/javascript">
30334 * @class Roo.QuickTips
30335 * Provides attractive and customizable tooltips for any element.
30338 Roo.QuickTips = function(){
30339 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30340 var ce, bd, xy, dd;
30341 var visible = false, disabled = true, inited = false;
30342 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30344 var onOver = function(e){
30348 var t = e.getTarget();
30349 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30352 if(ce && t == ce.el){
30353 clearTimeout(hideProc);
30356 if(t && tagEls[t.id]){
30357 tagEls[t.id].el = t;
30358 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30361 var ttp, et = Roo.fly(t);
30362 var ns = cfg.namespace;
30363 if(tm.interceptTitles && t.title){
30366 t.removeAttribute("title");
30367 e.preventDefault();
30369 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30372 showProc = show.defer(tm.showDelay, tm, [{
30375 width: et.getAttributeNS(ns, cfg.width),
30376 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30377 title: et.getAttributeNS(ns, cfg.title),
30378 cls: et.getAttributeNS(ns, cfg.cls)
30383 var onOut = function(e){
30384 clearTimeout(showProc);
30385 var t = e.getTarget();
30386 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30387 hideProc = setTimeout(hide, tm.hideDelay);
30391 var onMove = function(e){
30397 if(tm.trackMouse && ce){
30402 var onDown = function(e){
30403 clearTimeout(showProc);
30404 clearTimeout(hideProc);
30406 if(tm.hideOnClick){
30409 tm.enable.defer(100, tm);
30414 var getPad = function(){
30415 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30418 var show = function(o){
30422 clearTimeout(dismissProc);
30424 if(removeCls){ // in case manually hidden
30425 el.removeClass(removeCls);
30429 el.addClass(ce.cls);
30430 removeCls = ce.cls;
30433 tipTitle.update(ce.title);
30436 tipTitle.update('');
30439 el.dom.style.width = tm.maxWidth+'px';
30440 //tipBody.dom.style.width = '';
30441 tipBodyText.update(o.text);
30442 var p = getPad(), w = ce.width;
30444 var td = tipBodyText.dom;
30445 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30446 if(aw > tm.maxWidth){
30448 }else if(aw < tm.minWidth){
30454 //tipBody.setWidth(w);
30455 el.setWidth(parseInt(w, 10) + p);
30456 if(ce.autoHide === false){
30457 close.setDisplayed(true);
30462 close.setDisplayed(false);
30468 el.avoidY = xy[1]-18;
30473 el.setStyle("visibility", "visible");
30474 el.fadeIn({callback: afterShow});
30480 var afterShow = function(){
30484 if(tm.autoDismiss && ce.autoHide !== false){
30485 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30490 var hide = function(noanim){
30491 clearTimeout(dismissProc);
30492 clearTimeout(hideProc);
30494 if(el.isVisible()){
30496 if(noanim !== true && tm.animate){
30497 el.fadeOut({callback: afterHide});
30504 var afterHide = function(){
30507 el.removeClass(removeCls);
30514 * @cfg {Number} minWidth
30515 * The minimum width of the quick tip (defaults to 40)
30519 * @cfg {Number} maxWidth
30520 * The maximum width of the quick tip (defaults to 300)
30524 * @cfg {Boolean} interceptTitles
30525 * True to automatically use the element's DOM title value if available (defaults to false)
30527 interceptTitles : false,
30529 * @cfg {Boolean} trackMouse
30530 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30532 trackMouse : false,
30534 * @cfg {Boolean} hideOnClick
30535 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30537 hideOnClick : true,
30539 * @cfg {Number} showDelay
30540 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30544 * @cfg {Number} hideDelay
30545 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30549 * @cfg {Boolean} autoHide
30550 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30551 * Used in conjunction with hideDelay.
30556 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30557 * (defaults to true). Used in conjunction with autoDismissDelay.
30559 autoDismiss : true,
30562 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30564 autoDismissDelay : 5000,
30566 * @cfg {Boolean} animate
30567 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30572 * @cfg {String} title
30573 * Title text to display (defaults to ''). This can be any valid HTML markup.
30577 * @cfg {String} text
30578 * Body text to display (defaults to ''). This can be any valid HTML markup.
30582 * @cfg {String} cls
30583 * A CSS class to apply to the base quick tip element (defaults to '').
30587 * @cfg {Number} width
30588 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30589 * minWidth or maxWidth.
30594 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30595 * or display QuickTips in a page.
30598 tm = Roo.QuickTips;
30599 cfg = tm.tagConfig;
30601 if(!Roo.isReady){ // allow calling of init() before onReady
30602 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30605 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30606 el.fxDefaults = {stopFx: true};
30607 // maximum custom styling
30608 //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>');
30609 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>');
30610 tipTitle = el.child('h3');
30611 tipTitle.enableDisplayMode("block");
30612 tipBody = el.child('div.x-tip-bd');
30613 tipBodyText = el.child('div.x-tip-bd-inner');
30614 //bdLeft = el.child('div.x-tip-bd-left');
30615 //bdRight = el.child('div.x-tip-bd-right');
30616 close = el.child('div.x-tip-close');
30617 close.enableDisplayMode("block");
30618 close.on("click", hide);
30619 var d = Roo.get(document);
30620 d.on("mousedown", onDown);
30621 d.on("mouseover", onOver);
30622 d.on("mouseout", onOut);
30623 d.on("mousemove", onMove);
30624 esc = d.addKeyListener(27, hide);
30627 dd = el.initDD("default", null, {
30628 onDrag : function(){
30632 dd.setHandleElId(tipTitle.id);
30641 * Configures a new quick tip instance and assigns it to a target element. The following config options
30644 Property Type Description
30645 ---------- --------------------- ------------------------------------------------------------------------
30646 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30648 * @param {Object} config The config object
30650 register : function(config){
30651 var cs = config instanceof Array ? config : arguments;
30652 for(var i = 0, len = cs.length; i < len; i++) {
30654 var target = c.target;
30656 if(target instanceof Array){
30657 for(var j = 0, jlen = target.length; j < jlen; j++){
30658 tagEls[target[j]] = c;
30661 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30668 * Removes this quick tip from its element and destroys it.
30669 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30671 unregister : function(el){
30672 delete tagEls[Roo.id(el)];
30676 * Enable this quick tip.
30678 enable : function(){
30679 if(inited && disabled){
30681 if(locks.length < 1){
30688 * Disable this quick tip.
30690 disable : function(){
30692 clearTimeout(showProc);
30693 clearTimeout(hideProc);
30694 clearTimeout(dismissProc);
30702 * Returns true if the quick tip is enabled, else false.
30704 isEnabled : function(){
30711 attribute : "qtip",
30721 // backwards compat
30722 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30724 * Ext JS Library 1.1.1
30725 * Copyright(c) 2006-2007, Ext JS, LLC.
30727 * Originally Released Under LGPL - original licence link has changed is not relivant.
30730 * <script type="text/javascript">
30735 * @class Roo.tree.TreePanel
30736 * @extends Roo.data.Tree
30738 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30739 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30740 * @cfg {Boolean} enableDD true to enable drag and drop
30741 * @cfg {Boolean} enableDrag true to enable just drag
30742 * @cfg {Boolean} enableDrop true to enable just drop
30743 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30744 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30745 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30746 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30747 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30748 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30749 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30750 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30751 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30752 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30753 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30754 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30755 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30756 * @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>
30757 * @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>
30760 * @param {String/HTMLElement/Element} el The container element
30761 * @param {Object} config
30763 Roo.tree.TreePanel = function(el, config){
30765 var loader = false;
30767 root = config.root;
30768 delete config.root;
30770 if (config.loader) {
30771 loader = config.loader;
30772 delete config.loader;
30775 Roo.apply(this, config);
30776 Roo.tree.TreePanel.superclass.constructor.call(this);
30777 this.el = Roo.get(el);
30778 this.el.addClass('x-tree');
30779 //console.log(root);
30781 this.setRootNode( Roo.factory(root, Roo.tree));
30784 this.loader = Roo.factory(loader, Roo.tree);
30787 * Read-only. The id of the container element becomes this TreePanel's id.
30789 this.id = this.el.id;
30792 * @event beforeload
30793 * Fires before a node is loaded, return false to cancel
30794 * @param {Node} node The node being loaded
30796 "beforeload" : true,
30799 * Fires when a node is loaded
30800 * @param {Node} node The node that was loaded
30804 * @event textchange
30805 * Fires when the text for a node is changed
30806 * @param {Node} node The node
30807 * @param {String} text The new text
30808 * @param {String} oldText The old text
30810 "textchange" : true,
30812 * @event beforeexpand
30813 * Fires before a node is expanded, return false to cancel.
30814 * @param {Node} node The node
30815 * @param {Boolean} deep
30816 * @param {Boolean} anim
30818 "beforeexpand" : true,
30820 * @event beforecollapse
30821 * Fires before a node is collapsed, return false to cancel.
30822 * @param {Node} node The node
30823 * @param {Boolean} deep
30824 * @param {Boolean} anim
30826 "beforecollapse" : true,
30829 * Fires when a node is expanded
30830 * @param {Node} node The node
30834 * @event disabledchange
30835 * Fires when the disabled status of a node changes
30836 * @param {Node} node The node
30837 * @param {Boolean} disabled
30839 "disabledchange" : true,
30842 * Fires when a node is collapsed
30843 * @param {Node} node The node
30847 * @event beforeclick
30848 * Fires before click processing on a node. Return false to cancel the default action.
30849 * @param {Node} node The node
30850 * @param {Roo.EventObject} e The event object
30852 "beforeclick":true,
30854 * @event checkchange
30855 * Fires when a node with a checkbox's checked property changes
30856 * @param {Node} this This node
30857 * @param {Boolean} checked
30859 "checkchange":true,
30862 * Fires when a node is clicked
30863 * @param {Node} node The node
30864 * @param {Roo.EventObject} e The event object
30869 * Fires when a node is double clicked
30870 * @param {Node} node The node
30871 * @param {Roo.EventObject} e The event object
30875 * @event contextmenu
30876 * Fires when a node is right clicked
30877 * @param {Node} node The node
30878 * @param {Roo.EventObject} e The event object
30880 "contextmenu":true,
30882 * @event beforechildrenrendered
30883 * Fires right before the child nodes for a node are rendered
30884 * @param {Node} node The node
30886 "beforechildrenrendered":true,
30889 * Fires when a node starts being dragged
30890 * @param {Roo.tree.TreePanel} this
30891 * @param {Roo.tree.TreeNode} node
30892 * @param {event} e The raw browser event
30894 "startdrag" : true,
30897 * Fires when a drag operation is complete
30898 * @param {Roo.tree.TreePanel} this
30899 * @param {Roo.tree.TreeNode} node
30900 * @param {event} e The raw browser event
30905 * Fires when a dragged node is dropped on a valid DD target
30906 * @param {Roo.tree.TreePanel} this
30907 * @param {Roo.tree.TreeNode} node
30908 * @param {DD} dd The dd it was dropped on
30909 * @param {event} e The raw browser event
30913 * @event beforenodedrop
30914 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30915 * passed to handlers has the following properties:<br />
30916 * <ul style="padding:5px;padding-left:16px;">
30917 * <li>tree - The TreePanel</li>
30918 * <li>target - The node being targeted for the drop</li>
30919 * <li>data - The drag data from the drag source</li>
30920 * <li>point - The point of the drop - append, above or below</li>
30921 * <li>source - The drag source</li>
30922 * <li>rawEvent - Raw mouse event</li>
30923 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30924 * to be inserted by setting them on this object.</li>
30925 * <li>cancel - Set this to true to cancel the drop.</li>
30927 * @param {Object} dropEvent
30929 "beforenodedrop" : true,
30932 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30933 * passed to handlers has the following properties:<br />
30934 * <ul style="padding:5px;padding-left:16px;">
30935 * <li>tree - The TreePanel</li>
30936 * <li>target - The node being targeted for the drop</li>
30937 * <li>data - The drag data from the drag source</li>
30938 * <li>point - The point of the drop - append, above or below</li>
30939 * <li>source - The drag source</li>
30940 * <li>rawEvent - Raw mouse event</li>
30941 * <li>dropNode - Dropped node(s).</li>
30943 * @param {Object} dropEvent
30947 * @event nodedragover
30948 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30949 * passed to handlers has the following properties:<br />
30950 * <ul style="padding:5px;padding-left:16px;">
30951 * <li>tree - The TreePanel</li>
30952 * <li>target - The node being targeted for the drop</li>
30953 * <li>data - The drag data from the drag source</li>
30954 * <li>point - The point of the drop - append, above or below</li>
30955 * <li>source - The drag source</li>
30956 * <li>rawEvent - Raw mouse event</li>
30957 * <li>dropNode - Drop node(s) provided by the source.</li>
30958 * <li>cancel - Set this to true to signal drop not allowed.</li>
30960 * @param {Object} dragOverEvent
30962 "nodedragover" : true
30965 if(this.singleExpand){
30966 this.on("beforeexpand", this.restrictExpand, this);
30969 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30970 rootVisible : true,
30971 animate: Roo.enableFx,
30974 hlDrop : Roo.enableFx,
30978 rendererTip: false,
30980 restrictExpand : function(node){
30981 var p = node.parentNode;
30983 if(p.expandedChild && p.expandedChild.parentNode == p){
30984 p.expandedChild.collapse();
30986 p.expandedChild = node;
30990 // private override
30991 setRootNode : function(node){
30992 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30993 if(!this.rootVisible){
30994 node.ui = new Roo.tree.RootTreeNodeUI(node);
31000 * Returns the container element for this TreePanel
31002 getEl : function(){
31007 * Returns the default TreeLoader for this TreePanel
31009 getLoader : function(){
31010 return this.loader;
31016 expandAll : function(){
31017 this.root.expand(true);
31021 * Collapse all nodes
31023 collapseAll : function(){
31024 this.root.collapse(true);
31028 * Returns the selection model used by this TreePanel
31030 getSelectionModel : function(){
31031 if(!this.selModel){
31032 this.selModel = new Roo.tree.DefaultSelectionModel();
31034 return this.selModel;
31038 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31039 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31040 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31043 getChecked : function(a, startNode){
31044 startNode = startNode || this.root;
31046 var f = function(){
31047 if(this.attributes.checked){
31048 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31051 startNode.cascade(f);
31056 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31057 * @param {String} path
31058 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31059 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31060 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31062 expandPath : function(path, attr, callback){
31063 attr = attr || "id";
31064 var keys = path.split(this.pathSeparator);
31065 var curNode = this.root;
31066 if(curNode.attributes[attr] != keys[1]){ // invalid root
31068 callback(false, null);
31073 var f = function(){
31074 if(++index == keys.length){
31076 callback(true, curNode);
31080 var c = curNode.findChild(attr, keys[index]);
31083 callback(false, curNode);
31088 c.expand(false, false, f);
31090 curNode.expand(false, false, f);
31094 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31095 * @param {String} path
31096 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31097 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31098 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31100 selectPath : function(path, attr, callback){
31101 attr = attr || "id";
31102 var keys = path.split(this.pathSeparator);
31103 var v = keys.pop();
31104 if(keys.length > 0){
31105 var f = function(success, node){
31106 if(success && node){
31107 var n = node.findChild(attr, v);
31113 }else if(callback){
31114 callback(false, n);
31118 callback(false, n);
31122 this.expandPath(keys.join(this.pathSeparator), attr, f);
31124 this.root.select();
31126 callback(true, this.root);
31131 getTreeEl : function(){
31136 * Trigger rendering of this TreePanel
31138 render : function(){
31139 if (this.innerCt) {
31140 return this; // stop it rendering more than once!!
31143 this.innerCt = this.el.createChild({tag:"ul",
31144 cls:"x-tree-root-ct " +
31145 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31147 if(this.containerScroll){
31148 Roo.dd.ScrollManager.register(this.el);
31150 if((this.enableDD || this.enableDrop) && !this.dropZone){
31152 * The dropZone used by this tree if drop is enabled
31153 * @type Roo.tree.TreeDropZone
31155 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31156 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31159 if((this.enableDD || this.enableDrag) && !this.dragZone){
31161 * The dragZone used by this tree if drag is enabled
31162 * @type Roo.tree.TreeDragZone
31164 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31165 ddGroup: this.ddGroup || "TreeDD",
31166 scroll: this.ddScroll
31169 this.getSelectionModel().init(this);
31171 console.log("ROOT not set in tree");
31174 this.root.render();
31175 if(!this.rootVisible){
31176 this.root.renderChildren();
31182 * Ext JS Library 1.1.1
31183 * Copyright(c) 2006-2007, Ext JS, LLC.
31185 * Originally Released Under LGPL - original licence link has changed is not relivant.
31188 * <script type="text/javascript">
31193 * @class Roo.tree.DefaultSelectionModel
31194 * @extends Roo.util.Observable
31195 * The default single selection for a TreePanel.
31197 Roo.tree.DefaultSelectionModel = function(){
31198 this.selNode = null;
31202 * @event selectionchange
31203 * Fires when the selected node changes
31204 * @param {DefaultSelectionModel} this
31205 * @param {TreeNode} node the new selection
31207 "selectionchange" : true,
31210 * @event beforeselect
31211 * Fires before the selected node changes, return false to cancel the change
31212 * @param {DefaultSelectionModel} this
31213 * @param {TreeNode} node the new selection
31214 * @param {TreeNode} node the old selection
31216 "beforeselect" : true
31220 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31221 init : function(tree){
31223 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31224 tree.on("click", this.onNodeClick, this);
31227 onNodeClick : function(node, e){
31228 if (e.ctrlKey && this.selNode == node) {
31229 this.unselect(node);
31237 * @param {TreeNode} node The node to select
31238 * @return {TreeNode} The selected node
31240 select : function(node){
31241 var last = this.selNode;
31242 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31244 last.ui.onSelectedChange(false);
31246 this.selNode = node;
31247 node.ui.onSelectedChange(true);
31248 this.fireEvent("selectionchange", this, node, last);
31255 * @param {TreeNode} node The node to unselect
31257 unselect : function(node){
31258 if(this.selNode == node){
31259 this.clearSelections();
31264 * Clear all selections
31266 clearSelections : function(){
31267 var n = this.selNode;
31269 n.ui.onSelectedChange(false);
31270 this.selNode = null;
31271 this.fireEvent("selectionchange", this, null);
31277 * Get the selected node
31278 * @return {TreeNode} The selected node
31280 getSelectedNode : function(){
31281 return this.selNode;
31285 * Returns true if the node is selected
31286 * @param {TreeNode} node The node to check
31287 * @return {Boolean}
31289 isSelected : function(node){
31290 return this.selNode == node;
31294 * Selects the node above the selected node in the tree, intelligently walking the nodes
31295 * @return TreeNode The new selection
31297 selectPrevious : function(){
31298 var s = this.selNode || this.lastSelNode;
31302 var ps = s.previousSibling;
31304 if(!ps.isExpanded() || ps.childNodes.length < 1){
31305 return this.select(ps);
31307 var lc = ps.lastChild;
31308 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31311 return this.select(lc);
31313 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31314 return this.select(s.parentNode);
31320 * Selects the node above the selected node in the tree, intelligently walking the nodes
31321 * @return TreeNode The new selection
31323 selectNext : function(){
31324 var s = this.selNode || this.lastSelNode;
31328 if(s.firstChild && s.isExpanded()){
31329 return this.select(s.firstChild);
31330 }else if(s.nextSibling){
31331 return this.select(s.nextSibling);
31332 }else if(s.parentNode){
31334 s.parentNode.bubble(function(){
31335 if(this.nextSibling){
31336 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31345 onKeyDown : function(e){
31346 var s = this.selNode || this.lastSelNode;
31347 // undesirable, but required
31352 var k = e.getKey();
31360 this.selectPrevious();
31363 e.preventDefault();
31364 if(s.hasChildNodes()){
31365 if(!s.isExpanded()){
31367 }else if(s.firstChild){
31368 this.select(s.firstChild, e);
31373 e.preventDefault();
31374 if(s.hasChildNodes() && s.isExpanded()){
31376 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31377 this.select(s.parentNode, e);
31385 * @class Roo.tree.MultiSelectionModel
31386 * @extends Roo.util.Observable
31387 * Multi selection for a TreePanel.
31389 Roo.tree.MultiSelectionModel = function(){
31390 this.selNodes = [];
31394 * @event selectionchange
31395 * Fires when the selected nodes change
31396 * @param {MultiSelectionModel} this
31397 * @param {Array} nodes Array of the selected nodes
31399 "selectionchange" : true
31403 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31404 init : function(tree){
31406 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31407 tree.on("click", this.onNodeClick, this);
31410 onNodeClick : function(node, e){
31411 this.select(node, e, e.ctrlKey);
31416 * @param {TreeNode} node The node to select
31417 * @param {EventObject} e (optional) An event associated with the selection
31418 * @param {Boolean} keepExisting True to retain existing selections
31419 * @return {TreeNode} The selected node
31421 select : function(node, e, keepExisting){
31422 if(keepExisting !== true){
31423 this.clearSelections(true);
31425 if(this.isSelected(node)){
31426 this.lastSelNode = node;
31429 this.selNodes.push(node);
31430 this.selMap[node.id] = node;
31431 this.lastSelNode = node;
31432 node.ui.onSelectedChange(true);
31433 this.fireEvent("selectionchange", this, this.selNodes);
31439 * @param {TreeNode} node The node to unselect
31441 unselect : function(node){
31442 if(this.selMap[node.id]){
31443 node.ui.onSelectedChange(false);
31444 var sn = this.selNodes;
31447 index = sn.indexOf(node);
31449 for(var i = 0, len = sn.length; i < len; i++){
31457 this.selNodes.splice(index, 1);
31459 delete this.selMap[node.id];
31460 this.fireEvent("selectionchange", this, this.selNodes);
31465 * Clear all selections
31467 clearSelections : function(suppressEvent){
31468 var sn = this.selNodes;
31470 for(var i = 0, len = sn.length; i < len; i++){
31471 sn[i].ui.onSelectedChange(false);
31473 this.selNodes = [];
31475 if(suppressEvent !== true){
31476 this.fireEvent("selectionchange", this, this.selNodes);
31482 * Returns true if the node is selected
31483 * @param {TreeNode} node The node to check
31484 * @return {Boolean}
31486 isSelected : function(node){
31487 return this.selMap[node.id] ? true : false;
31491 * Returns an array of the selected nodes
31494 getSelectedNodes : function(){
31495 return this.selNodes;
31498 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31500 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31502 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31505 * Ext JS Library 1.1.1
31506 * Copyright(c) 2006-2007, Ext JS, LLC.
31508 * Originally Released Under LGPL - original licence link has changed is not relivant.
31511 * <script type="text/javascript">
31515 * @class Roo.tree.TreeNode
31516 * @extends Roo.data.Node
31517 * @cfg {String} text The text for this node
31518 * @cfg {Boolean} expanded true to start the node expanded
31519 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31520 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31521 * @cfg {Boolean} disabled true to start the node disabled
31522 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31523 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31524 * @cfg {String} cls A css class to be added to the node
31525 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31526 * @cfg {String} href URL of the link used for the node (defaults to #)
31527 * @cfg {String} hrefTarget target frame for the link
31528 * @cfg {String} qtip An Ext QuickTip for the node
31529 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31530 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31531 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31532 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31533 * (defaults to undefined with no checkbox rendered)
31535 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31537 Roo.tree.TreeNode = function(attributes){
31538 attributes = attributes || {};
31539 if(typeof attributes == "string"){
31540 attributes = {text: attributes};
31542 this.childrenRendered = false;
31543 this.rendered = false;
31544 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31545 this.expanded = attributes.expanded === true;
31546 this.isTarget = attributes.isTarget !== false;
31547 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31548 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31551 * Read-only. The text for this node. To change it use setText().
31554 this.text = attributes.text;
31556 * True if this node is disabled.
31559 this.disabled = attributes.disabled === true;
31563 * @event textchange
31564 * Fires when the text for this node is changed
31565 * @param {Node} this This node
31566 * @param {String} text The new text
31567 * @param {String} oldText The old text
31569 "textchange" : true,
31571 * @event beforeexpand
31572 * Fires before this node is expanded, return false to cancel.
31573 * @param {Node} this This node
31574 * @param {Boolean} deep
31575 * @param {Boolean} anim
31577 "beforeexpand" : true,
31579 * @event beforecollapse
31580 * Fires before this node is collapsed, return false to cancel.
31581 * @param {Node} this This node
31582 * @param {Boolean} deep
31583 * @param {Boolean} anim
31585 "beforecollapse" : true,
31588 * Fires when this node is expanded
31589 * @param {Node} this This node
31593 * @event disabledchange
31594 * Fires when the disabled status of this node changes
31595 * @param {Node} this This node
31596 * @param {Boolean} disabled
31598 "disabledchange" : true,
31601 * Fires when this node is collapsed
31602 * @param {Node} this This node
31606 * @event beforeclick
31607 * Fires before click processing. Return false to cancel the default action.
31608 * @param {Node} this This node
31609 * @param {Roo.EventObject} e The event object
31611 "beforeclick":true,
31613 * @event checkchange
31614 * Fires when a node with a checkbox's checked property changes
31615 * @param {Node} this This node
31616 * @param {Boolean} checked
31618 "checkchange":true,
31621 * Fires when this node is clicked
31622 * @param {Node} this This node
31623 * @param {Roo.EventObject} e The event object
31628 * Fires when this node is double clicked
31629 * @param {Node} this This node
31630 * @param {Roo.EventObject} e The event object
31634 * @event contextmenu
31635 * Fires when this node is right clicked
31636 * @param {Node} this This node
31637 * @param {Roo.EventObject} e The event object
31639 "contextmenu":true,
31641 * @event beforechildrenrendered
31642 * Fires right before the child nodes for this node are rendered
31643 * @param {Node} this This node
31645 "beforechildrenrendered":true
31648 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31651 * Read-only. The UI for this node
31654 this.ui = new uiClass(this);
31656 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31657 preventHScroll: true,
31659 * Returns true if this node is expanded
31660 * @return {Boolean}
31662 isExpanded : function(){
31663 return this.expanded;
31667 * Returns the UI object for this node
31668 * @return {TreeNodeUI}
31670 getUI : function(){
31674 // private override
31675 setFirstChild : function(node){
31676 var of = this.firstChild;
31677 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31678 if(this.childrenRendered && of && node != of){
31679 of.renderIndent(true, true);
31682 this.renderIndent(true, true);
31686 // private override
31687 setLastChild : function(node){
31688 var ol = this.lastChild;
31689 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31690 if(this.childrenRendered && ol && node != ol){
31691 ol.renderIndent(true, true);
31694 this.renderIndent(true, true);
31698 // these methods are overridden to provide lazy rendering support
31699 // private override
31700 appendChild : function(){
31701 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31702 if(node && this.childrenRendered){
31705 this.ui.updateExpandIcon();
31709 // private override
31710 removeChild : function(node){
31711 this.ownerTree.getSelectionModel().unselect(node);
31712 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31713 // if it's been rendered remove dom node
31714 if(this.childrenRendered){
31717 if(this.childNodes.length < 1){
31718 this.collapse(false, false);
31720 this.ui.updateExpandIcon();
31722 if(!this.firstChild) {
31723 this.childrenRendered = false;
31728 // private override
31729 insertBefore : function(node, refNode){
31730 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31731 if(newNode && refNode && this.childrenRendered){
31734 this.ui.updateExpandIcon();
31739 * Sets the text for this node
31740 * @param {String} text
31742 setText : function(text){
31743 var oldText = this.text;
31745 this.attributes.text = text;
31746 if(this.rendered){ // event without subscribing
31747 this.ui.onTextChange(this, text, oldText);
31749 this.fireEvent("textchange", this, text, oldText);
31753 * Triggers selection of this node
31755 select : function(){
31756 this.getOwnerTree().getSelectionModel().select(this);
31760 * Triggers deselection of this node
31762 unselect : function(){
31763 this.getOwnerTree().getSelectionModel().unselect(this);
31767 * Returns true if this node is selected
31768 * @return {Boolean}
31770 isSelected : function(){
31771 return this.getOwnerTree().getSelectionModel().isSelected(this);
31775 * Expand this node.
31776 * @param {Boolean} deep (optional) True to expand all children as well
31777 * @param {Boolean} anim (optional) false to cancel the default animation
31778 * @param {Function} callback (optional) A callback to be called when
31779 * expanding this node completes (does not wait for deep expand to complete).
31780 * Called with 1 parameter, this node.
31782 expand : function(deep, anim, callback){
31783 if(!this.expanded){
31784 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31787 if(!this.childrenRendered){
31788 this.renderChildren();
31790 this.expanded = true;
31791 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31792 this.ui.animExpand(function(){
31793 this.fireEvent("expand", this);
31794 if(typeof callback == "function"){
31798 this.expandChildNodes(true);
31800 }.createDelegate(this));
31804 this.fireEvent("expand", this);
31805 if(typeof callback == "function"){
31810 if(typeof callback == "function"){
31815 this.expandChildNodes(true);
31819 isHiddenRoot : function(){
31820 return this.isRoot && !this.getOwnerTree().rootVisible;
31824 * Collapse this node.
31825 * @param {Boolean} deep (optional) True to collapse all children as well
31826 * @param {Boolean} anim (optional) false to cancel the default animation
31828 collapse : function(deep, anim){
31829 if(this.expanded && !this.isHiddenRoot()){
31830 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31833 this.expanded = false;
31834 if((this.getOwnerTree().animate && anim !== false) || anim){
31835 this.ui.animCollapse(function(){
31836 this.fireEvent("collapse", this);
31838 this.collapseChildNodes(true);
31840 }.createDelegate(this));
31843 this.ui.collapse();
31844 this.fireEvent("collapse", this);
31848 var cs = this.childNodes;
31849 for(var i = 0, len = cs.length; i < len; i++) {
31850 cs[i].collapse(true, false);
31856 delayedExpand : function(delay){
31857 if(!this.expandProcId){
31858 this.expandProcId = this.expand.defer(delay, this);
31863 cancelExpand : function(){
31864 if(this.expandProcId){
31865 clearTimeout(this.expandProcId);
31867 this.expandProcId = false;
31871 * Toggles expanded/collapsed state of the node
31873 toggle : function(){
31882 * Ensures all parent nodes are expanded
31884 ensureVisible : function(callback){
31885 var tree = this.getOwnerTree();
31886 tree.expandPath(this.parentNode.getPath(), false, function(){
31887 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31888 Roo.callback(callback);
31889 }.createDelegate(this));
31893 * Expand all child nodes
31894 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31896 expandChildNodes : function(deep){
31897 var cs = this.childNodes;
31898 for(var i = 0, len = cs.length; i < len; i++) {
31899 cs[i].expand(deep);
31904 * Collapse all child nodes
31905 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31907 collapseChildNodes : function(deep){
31908 var cs = this.childNodes;
31909 for(var i = 0, len = cs.length; i < len; i++) {
31910 cs[i].collapse(deep);
31915 * Disables this node
31917 disable : function(){
31918 this.disabled = true;
31920 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31921 this.ui.onDisableChange(this, true);
31923 this.fireEvent("disabledchange", this, true);
31927 * Enables this node
31929 enable : function(){
31930 this.disabled = false;
31931 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31932 this.ui.onDisableChange(this, false);
31934 this.fireEvent("disabledchange", this, false);
31938 renderChildren : function(suppressEvent){
31939 if(suppressEvent !== false){
31940 this.fireEvent("beforechildrenrendered", this);
31942 var cs = this.childNodes;
31943 for(var i = 0, len = cs.length; i < len; i++){
31944 cs[i].render(true);
31946 this.childrenRendered = true;
31950 sort : function(fn, scope){
31951 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31952 if(this.childrenRendered){
31953 var cs = this.childNodes;
31954 for(var i = 0, len = cs.length; i < len; i++){
31955 cs[i].render(true);
31961 render : function(bulkRender){
31962 this.ui.render(bulkRender);
31963 if(!this.rendered){
31964 this.rendered = true;
31966 this.expanded = false;
31967 this.expand(false, false);
31973 renderIndent : function(deep, refresh){
31975 this.ui.childIndent = null;
31977 this.ui.renderIndent();
31978 if(deep === true && this.childrenRendered){
31979 var cs = this.childNodes;
31980 for(var i = 0, len = cs.length; i < len; i++){
31981 cs[i].renderIndent(true, refresh);
31987 * Ext JS Library 1.1.1
31988 * Copyright(c) 2006-2007, Ext JS, LLC.
31990 * Originally Released Under LGPL - original licence link has changed is not relivant.
31993 * <script type="text/javascript">
31997 * @class Roo.tree.AsyncTreeNode
31998 * @extends Roo.tree.TreeNode
31999 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32001 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32003 Roo.tree.AsyncTreeNode = function(config){
32004 this.loaded = false;
32005 this.loading = false;
32006 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32008 * @event beforeload
32009 * Fires before this node is loaded, return false to cancel
32010 * @param {Node} this This node
32012 this.addEvents({'beforeload':true, 'load': true});
32015 * Fires when this node is loaded
32016 * @param {Node} this This node
32019 * The loader used by this node (defaults to using the tree's defined loader)
32024 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32025 expand : function(deep, anim, callback){
32026 if(this.loading){ // if an async load is already running, waiting til it's done
32028 var f = function(){
32029 if(!this.loading){ // done loading
32030 clearInterval(timer);
32031 this.expand(deep, anim, callback);
32033 }.createDelegate(this);
32034 timer = setInterval(f, 200);
32038 if(this.fireEvent("beforeload", this) === false){
32041 this.loading = true;
32042 this.ui.beforeLoad(this);
32043 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32045 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32049 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32053 * Returns true if this node is currently loading
32054 * @return {Boolean}
32056 isLoading : function(){
32057 return this.loading;
32060 loadComplete : function(deep, anim, callback){
32061 this.loading = false;
32062 this.loaded = true;
32063 this.ui.afterLoad(this);
32064 this.fireEvent("load", this);
32065 this.expand(deep, anim, callback);
32069 * Returns true if this node has been loaded
32070 * @return {Boolean}
32072 isLoaded : function(){
32073 return this.loaded;
32076 hasChildNodes : function(){
32077 if(!this.isLeaf() && !this.loaded){
32080 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32085 * Trigger a reload for this node
32086 * @param {Function} callback
32088 reload : function(callback){
32089 this.collapse(false, false);
32090 while(this.firstChild){
32091 this.removeChild(this.firstChild);
32093 this.childrenRendered = false;
32094 this.loaded = false;
32095 if(this.isHiddenRoot()){
32096 this.expanded = false;
32098 this.expand(false, false, callback);
32102 * Ext JS Library 1.1.1
32103 * Copyright(c) 2006-2007, Ext JS, LLC.
32105 * Originally Released Under LGPL - original licence link has changed is not relivant.
32108 * <script type="text/javascript">
32112 * @class Roo.tree.TreeNodeUI
32114 * @param {Object} node The node to render
32115 * The TreeNode UI implementation is separate from the
32116 * tree implementation. Unless you are customizing the tree UI,
32117 * you should never have to use this directly.
32119 Roo.tree.TreeNodeUI = function(node){
32121 this.rendered = false;
32122 this.animating = false;
32123 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32126 Roo.tree.TreeNodeUI.prototype = {
32127 removeChild : function(node){
32129 this.ctNode.removeChild(node.ui.getEl());
32133 beforeLoad : function(){
32134 this.addClass("x-tree-node-loading");
32137 afterLoad : function(){
32138 this.removeClass("x-tree-node-loading");
32141 onTextChange : function(node, text, oldText){
32143 this.textNode.innerHTML = text;
32147 onDisableChange : function(node, state){
32148 this.disabled = state;
32150 this.addClass("x-tree-node-disabled");
32152 this.removeClass("x-tree-node-disabled");
32156 onSelectedChange : function(state){
32159 this.addClass("x-tree-selected");
32162 this.removeClass("x-tree-selected");
32166 onMove : function(tree, node, oldParent, newParent, index, refNode){
32167 this.childIndent = null;
32169 var targetNode = newParent.ui.getContainer();
32170 if(!targetNode){//target not rendered
32171 this.holder = document.createElement("div");
32172 this.holder.appendChild(this.wrap);
32175 var insertBefore = refNode ? refNode.ui.getEl() : null;
32177 targetNode.insertBefore(this.wrap, insertBefore);
32179 targetNode.appendChild(this.wrap);
32181 this.node.renderIndent(true);
32185 addClass : function(cls){
32187 Roo.fly(this.elNode).addClass(cls);
32191 removeClass : function(cls){
32193 Roo.fly(this.elNode).removeClass(cls);
32197 remove : function(){
32199 this.holder = document.createElement("div");
32200 this.holder.appendChild(this.wrap);
32204 fireEvent : function(){
32205 return this.node.fireEvent.apply(this.node, arguments);
32208 initEvents : function(){
32209 this.node.on("move", this.onMove, this);
32210 var E = Roo.EventManager;
32211 var a = this.anchor;
32213 var el = Roo.fly(a, '_treeui');
32215 if(Roo.isOpera){ // opera render bug ignores the CSS
32216 el.setStyle("text-decoration", "none");
32219 el.on("click", this.onClick, this);
32220 el.on("dblclick", this.onDblClick, this);
32223 Roo.EventManager.on(this.checkbox,
32224 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32227 el.on("contextmenu", this.onContextMenu, this);
32229 var icon = Roo.fly(this.iconNode);
32230 icon.on("click", this.onClick, this);
32231 icon.on("dblclick", this.onDblClick, this);
32232 icon.on("contextmenu", this.onContextMenu, this);
32233 E.on(this.ecNode, "click", this.ecClick, this, true);
32235 if(this.node.disabled){
32236 this.addClass("x-tree-node-disabled");
32238 if(this.node.hidden){
32239 this.addClass("x-tree-node-disabled");
32241 var ot = this.node.getOwnerTree();
32242 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32243 if(dd && (!this.node.isRoot || ot.rootVisible)){
32244 Roo.dd.Registry.register(this.elNode, {
32246 handles: this.getDDHandles(),
32252 getDDHandles : function(){
32253 return [this.iconNode, this.textNode];
32258 this.wrap.style.display = "none";
32264 this.wrap.style.display = "";
32268 onContextMenu : function(e){
32269 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32270 e.preventDefault();
32272 this.fireEvent("contextmenu", this.node, e);
32276 onClick : function(e){
32281 if(this.fireEvent("beforeclick", this.node, e) !== false){
32282 if(!this.disabled && this.node.attributes.href){
32283 this.fireEvent("click", this.node, e);
32286 e.preventDefault();
32291 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32292 this.node.toggle();
32295 this.fireEvent("click", this.node, e);
32301 onDblClick : function(e){
32302 e.preventDefault();
32307 this.toggleCheck();
32309 if(!this.animating && this.node.hasChildNodes()){
32310 this.node.toggle();
32312 this.fireEvent("dblclick", this.node, e);
32315 onCheckChange : function(){
32316 var checked = this.checkbox.checked;
32317 this.node.attributes.checked = checked;
32318 this.fireEvent('checkchange', this.node, checked);
32321 ecClick : function(e){
32322 if(!this.animating && this.node.hasChildNodes()){
32323 this.node.toggle();
32327 startDrop : function(){
32328 this.dropping = true;
32331 // delayed drop so the click event doesn't get fired on a drop
32332 endDrop : function(){
32333 setTimeout(function(){
32334 this.dropping = false;
32335 }.createDelegate(this), 50);
32338 expand : function(){
32339 this.updateExpandIcon();
32340 this.ctNode.style.display = "";
32343 focus : function(){
32344 if(!this.node.preventHScroll){
32345 try{this.anchor.focus();
32347 }else if(!Roo.isIE){
32349 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32350 var l = noscroll.scrollLeft;
32351 this.anchor.focus();
32352 noscroll.scrollLeft = l;
32357 toggleCheck : function(value){
32358 var cb = this.checkbox;
32360 cb.checked = (value === undefined ? !cb.checked : value);
32366 this.anchor.blur();
32370 animExpand : function(callback){
32371 var ct = Roo.get(this.ctNode);
32373 if(!this.node.hasChildNodes()){
32374 this.updateExpandIcon();
32375 this.ctNode.style.display = "";
32376 Roo.callback(callback);
32379 this.animating = true;
32380 this.updateExpandIcon();
32383 callback : function(){
32384 this.animating = false;
32385 Roo.callback(callback);
32388 duration: this.node.ownerTree.duration || .25
32392 highlight : function(){
32393 var tree = this.node.getOwnerTree();
32394 Roo.fly(this.wrap).highlight(
32395 tree.hlColor || "C3DAF9",
32396 {endColor: tree.hlBaseColor}
32400 collapse : function(){
32401 this.updateExpandIcon();
32402 this.ctNode.style.display = "none";
32405 animCollapse : function(callback){
32406 var ct = Roo.get(this.ctNode);
32407 ct.enableDisplayMode('block');
32410 this.animating = true;
32411 this.updateExpandIcon();
32414 callback : function(){
32415 this.animating = false;
32416 Roo.callback(callback);
32419 duration: this.node.ownerTree.duration || .25
32423 getContainer : function(){
32424 return this.ctNode;
32427 getEl : function(){
32431 appendDDGhost : function(ghostNode){
32432 ghostNode.appendChild(this.elNode.cloneNode(true));
32435 getDDRepairXY : function(){
32436 return Roo.lib.Dom.getXY(this.iconNode);
32439 onRender : function(){
32443 render : function(bulkRender){
32444 var n = this.node, a = n.attributes;
32445 var targetNode = n.parentNode ?
32446 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32448 if(!this.rendered){
32449 this.rendered = true;
32451 this.renderElements(n, a, targetNode, bulkRender);
32454 if(this.textNode.setAttributeNS){
32455 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32457 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32460 this.textNode.setAttribute("ext:qtip", a.qtip);
32462 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32465 }else if(a.qtipCfg){
32466 a.qtipCfg.target = Roo.id(this.textNode);
32467 Roo.QuickTips.register(a.qtipCfg);
32470 if(!this.node.expanded){
32471 this.updateExpandIcon();
32474 if(bulkRender === true) {
32475 targetNode.appendChild(this.wrap);
32480 renderElements : function(n, a, targetNode, bulkRender){
32481 // add some indent caching, this helps performance when rendering a large tree
32482 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32483 var t = n.getOwnerTree();
32484 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32485 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32486 var cb = typeof a.checked == 'boolean';
32487 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32488 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32489 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32490 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32491 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32492 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32493 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32494 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32495 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32496 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32499 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32500 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32501 n.nextSibling.ui.getEl(), buf.join(""));
32503 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32506 this.elNode = this.wrap.childNodes[0];
32507 this.ctNode = this.wrap.childNodes[1];
32508 var cs = this.elNode.childNodes;
32509 this.indentNode = cs[0];
32510 this.ecNode = cs[1];
32511 this.iconNode = cs[2];
32514 this.checkbox = cs[3];
32517 this.anchor = cs[index];
32518 this.textNode = cs[index].firstChild;
32521 getAnchor : function(){
32522 return this.anchor;
32525 getTextEl : function(){
32526 return this.textNode;
32529 getIconEl : function(){
32530 return this.iconNode;
32533 isChecked : function(){
32534 return this.checkbox ? this.checkbox.checked : false;
32537 updateExpandIcon : function(){
32539 var n = this.node, c1, c2;
32540 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32541 var hasChild = n.hasChildNodes();
32545 c1 = "x-tree-node-collapsed";
32546 c2 = "x-tree-node-expanded";
32549 c1 = "x-tree-node-expanded";
32550 c2 = "x-tree-node-collapsed";
32553 this.removeClass("x-tree-node-leaf");
32554 this.wasLeaf = false;
32556 if(this.c1 != c1 || this.c2 != c2){
32557 Roo.fly(this.elNode).replaceClass(c1, c2);
32558 this.c1 = c1; this.c2 = c2;
32562 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32565 this.wasLeaf = true;
32568 var ecc = "x-tree-ec-icon "+cls;
32569 if(this.ecc != ecc){
32570 this.ecNode.className = ecc;
32576 getChildIndent : function(){
32577 if(!this.childIndent){
32581 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32583 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32585 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32590 this.childIndent = buf.join("");
32592 return this.childIndent;
32595 renderIndent : function(){
32598 var p = this.node.parentNode;
32600 indent = p.ui.getChildIndent();
32602 if(this.indentMarkup != indent){ // don't rerender if not required
32603 this.indentNode.innerHTML = indent;
32604 this.indentMarkup = indent;
32606 this.updateExpandIcon();
32611 Roo.tree.RootTreeNodeUI = function(){
32612 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32614 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32615 render : function(){
32616 if(!this.rendered){
32617 var targetNode = this.node.ownerTree.innerCt.dom;
32618 this.node.expanded = true;
32619 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32620 this.wrap = this.ctNode = targetNode.firstChild;
32623 collapse : function(){
32625 expand : function(){
32629 * Ext JS Library 1.1.1
32630 * Copyright(c) 2006-2007, Ext JS, LLC.
32632 * Originally Released Under LGPL - original licence link has changed is not relivant.
32635 * <script type="text/javascript">
32638 * @class Roo.tree.TreeLoader
32639 * @extends Roo.util.Observable
32640 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32641 * nodes from a specified URL. The response must be a javascript Array definition
32642 * who's elements are node definition objects. eg:
32644 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32645 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32648 * A server request is sent, and child nodes are loaded only when a node is expanded.
32649 * The loading node's id is passed to the server under the parameter name "node" to
32650 * enable the server to produce the correct child nodes.
32652 * To pass extra parameters, an event handler may be attached to the "beforeload"
32653 * event, and the parameters specified in the TreeLoader's baseParams property:
32655 myTreeLoader.on("beforeload", function(treeLoader, node) {
32656 this.baseParams.category = node.attributes.category;
32659 * This would pass an HTTP parameter called "category" to the server containing
32660 * the value of the Node's "category" attribute.
32662 * Creates a new Treeloader.
32663 * @param {Object} config A config object containing config properties.
32665 Roo.tree.TreeLoader = function(config){
32666 this.baseParams = {};
32667 this.requestMethod = "POST";
32668 Roo.apply(this, config);
32673 * @event beforeload
32674 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32675 * @param {Object} This TreeLoader object.
32676 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32677 * @param {Object} callback The callback function specified in the {@link #load} call.
32682 * Fires when the node has been successfuly loaded.
32683 * @param {Object} This TreeLoader object.
32684 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32685 * @param {Object} response The response object containing the data from the server.
32689 * @event loadexception
32690 * Fires if the network request failed.
32691 * @param {Object} This TreeLoader object.
32692 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32693 * @param {Object} response The response object containing the data from the server.
32695 loadexception : true,
32698 * Fires before a node is created, enabling you to return custom Node types
32699 * @param {Object} This TreeLoader object.
32700 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32705 Roo.tree.TreeLoader.superclass.constructor.call(this);
32708 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32710 * @cfg {String} dataUrl The URL from which to request a Json string which
32711 * specifies an array of node definition object representing the child nodes
32715 * @cfg {Object} baseParams (optional) An object containing properties which
32716 * specify HTTP parameters to be passed to each request for child nodes.
32719 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32720 * created by this loader. If the attributes sent by the server have an attribute in this object,
32721 * they take priority.
32724 * @cfg {Object} uiProviders (optional) An object containing properties which
32726 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32727 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32728 * <i>uiProvider</i> attribute of a returned child node is a string rather
32729 * than a reference to a TreeNodeUI implementation, this that string value
32730 * is used as a property name in the uiProviders object. You can define the provider named
32731 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32736 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32737 * child nodes before loading.
32739 clearOnLoad : true,
32742 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32743 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32744 * Grid query { data : [ .....] }
32749 * @cfg {String} queryParam (optional)
32750 * Name of the query as it will be passed on the querystring (defaults to 'node')
32751 * eg. the request will be ?node=[id]
32758 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32759 * This is called automatically when a node is expanded, but may be used to reload
32760 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32761 * @param {Roo.tree.TreeNode} node
32762 * @param {Function} callback
32764 load : function(node, callback){
32765 if(this.clearOnLoad){
32766 while(node.firstChild){
32767 node.removeChild(node.firstChild);
32770 if(node.attributes.children){ // preloaded json children
32771 var cs = node.attributes.children;
32772 for(var i = 0, len = cs.length; i < len; i++){
32773 node.appendChild(this.createNode(cs[i]));
32775 if(typeof callback == "function"){
32778 }else if(this.dataUrl){
32779 this.requestData(node, callback);
32783 getParams: function(node){
32784 var buf = [], bp = this.baseParams;
32785 for(var key in bp){
32786 if(typeof bp[key] != "function"){
32787 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32790 var n = this.queryParam === false ? 'node' : this.queryParam;
32791 buf.push(n + "=", encodeURIComponent(node.id));
32792 return buf.join("");
32795 requestData : function(node, callback){
32796 if(this.fireEvent("beforeload", this, node, callback) !== false){
32797 this.transId = Roo.Ajax.request({
32798 method:this.requestMethod,
32799 url: this.dataUrl||this.url,
32800 success: this.handleResponse,
32801 failure: this.handleFailure,
32803 argument: {callback: callback, node: node},
32804 params: this.getParams(node)
32807 // if the load is cancelled, make sure we notify
32808 // the node that we are done
32809 if(typeof callback == "function"){
32815 isLoading : function(){
32816 return this.transId ? true : false;
32819 abort : function(){
32820 if(this.isLoading()){
32821 Roo.Ajax.abort(this.transId);
32826 createNode : function(attr){
32827 // apply baseAttrs, nice idea Corey!
32828 if(this.baseAttrs){
32829 Roo.applyIf(attr, this.baseAttrs);
32831 if(this.applyLoader !== false){
32832 attr.loader = this;
32834 // uiProvider = depreciated..
32836 if(typeof(attr.uiProvider) == 'string'){
32837 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32838 /** eval:var:attr */ eval(attr.uiProvider);
32840 if(typeof(this.uiProviders['default']) != 'undefined') {
32841 attr.uiProvider = this.uiProviders['default'];
32844 this.fireEvent('create', this, attr);
32846 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32848 new Roo.tree.TreeNode(attr) :
32849 new Roo.tree.AsyncTreeNode(attr));
32852 processResponse : function(response, node, callback){
32853 var json = response.responseText;
32856 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32857 if (this.root !== false) {
32861 for(var i = 0, len = o.length; i < len; i++){
32862 var n = this.createNode(o[i]);
32864 node.appendChild(n);
32867 if(typeof callback == "function"){
32868 callback(this, node);
32871 this.handleFailure(response);
32875 handleResponse : function(response){
32876 this.transId = false;
32877 var a = response.argument;
32878 this.processResponse(response, a.node, a.callback);
32879 this.fireEvent("load", this, a.node, response);
32882 handleFailure : function(response){
32883 this.transId = false;
32884 var a = response.argument;
32885 this.fireEvent("loadexception", this, a.node, response);
32886 if(typeof a.callback == "function"){
32887 a.callback(this, a.node);
32892 * Ext JS Library 1.1.1
32893 * Copyright(c) 2006-2007, Ext JS, LLC.
32895 * Originally Released Under LGPL - original licence link has changed is not relivant.
32898 * <script type="text/javascript">
32902 * @class Roo.tree.TreeFilter
32903 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32904 * @param {TreePanel} tree
32905 * @param {Object} config (optional)
32907 Roo.tree.TreeFilter = function(tree, config){
32909 this.filtered = {};
32910 Roo.apply(this, config);
32913 Roo.tree.TreeFilter.prototype = {
32920 * Filter the data by a specific attribute.
32921 * @param {String/RegExp} value Either string that the attribute value
32922 * should start with or a RegExp to test against the attribute
32923 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32924 * @param {TreeNode} startNode (optional) The node to start the filter at.
32926 filter : function(value, attr, startNode){
32927 attr = attr || "text";
32929 if(typeof value == "string"){
32930 var vlen = value.length;
32931 // auto clear empty filter
32932 if(vlen == 0 && this.clearBlank){
32936 value = value.toLowerCase();
32938 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32940 }else if(value.exec){ // regex?
32942 return value.test(n.attributes[attr]);
32945 throw 'Illegal filter type, must be string or regex';
32947 this.filterBy(f, null, startNode);
32951 * Filter by a function. The passed function will be called with each
32952 * node in the tree (or from the startNode). If the function returns true, the node is kept
32953 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32954 * @param {Function} fn The filter function
32955 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32957 filterBy : function(fn, scope, startNode){
32958 startNode = startNode || this.tree.root;
32959 if(this.autoClear){
32962 var af = this.filtered, rv = this.reverse;
32963 var f = function(n){
32964 if(n == startNode){
32970 var m = fn.call(scope || n, n);
32978 startNode.cascade(f);
32981 if(typeof id != "function"){
32983 if(n && n.parentNode){
32984 n.parentNode.removeChild(n);
32992 * Clears the current filter. Note: with the "remove" option
32993 * set a filter cannot be cleared.
32995 clear : function(){
32997 var af = this.filtered;
32999 if(typeof id != "function"){
33006 this.filtered = {};
33011 * Ext JS Library 1.1.1
33012 * Copyright(c) 2006-2007, Ext JS, LLC.
33014 * Originally Released Under LGPL - original licence link has changed is not relivant.
33017 * <script type="text/javascript">
33022 * @class Roo.tree.TreeSorter
33023 * Provides sorting of nodes in a TreePanel
33025 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33026 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33027 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33028 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33029 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33030 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33032 * @param {TreePanel} tree
33033 * @param {Object} config
33035 Roo.tree.TreeSorter = function(tree, config){
33036 Roo.apply(this, config);
33037 tree.on("beforechildrenrendered", this.doSort, this);
33038 tree.on("append", this.updateSort, this);
33039 tree.on("insert", this.updateSort, this);
33041 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33042 var p = this.property || "text";
33043 var sortType = this.sortType;
33044 var fs = this.folderSort;
33045 var cs = this.caseSensitive === true;
33046 var leafAttr = this.leafAttr || 'leaf';
33048 this.sortFn = function(n1, n2){
33050 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33053 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33057 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33058 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33060 return dsc ? +1 : -1;
33062 return dsc ? -1 : +1;
33069 Roo.tree.TreeSorter.prototype = {
33070 doSort : function(node){
33071 node.sort(this.sortFn);
33074 compareNodes : function(n1, n2){
33075 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33078 updateSort : function(tree, node){
33079 if(node.childrenRendered){
33080 this.doSort.defer(1, this, [node]);
33085 * Ext JS Library 1.1.1
33086 * Copyright(c) 2006-2007, Ext JS, LLC.
33088 * Originally Released Under LGPL - original licence link has changed is not relivant.
33091 * <script type="text/javascript">
33094 if(Roo.dd.DropZone){
33096 Roo.tree.TreeDropZone = function(tree, config){
33097 this.allowParentInsert = false;
33098 this.allowContainerDrop = false;
33099 this.appendOnly = false;
33100 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33102 this.lastInsertClass = "x-tree-no-status";
33103 this.dragOverData = {};
33106 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33107 ddGroup : "TreeDD",
33109 expandDelay : 1000,
33111 expandNode : function(node){
33112 if(node.hasChildNodes() && !node.isExpanded()){
33113 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33117 queueExpand : function(node){
33118 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33121 cancelExpand : function(){
33122 if(this.expandProcId){
33123 clearTimeout(this.expandProcId);
33124 this.expandProcId = false;
33128 isValidDropPoint : function(n, pt, dd, e, data){
33129 if(!n || !data){ return false; }
33130 var targetNode = n.node;
33131 var dropNode = data.node;
33132 // default drop rules
33133 if(!(targetNode && targetNode.isTarget && pt)){
33136 if(pt == "append" && targetNode.allowChildren === false){
33139 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33142 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33145 // reuse the object
33146 var overEvent = this.dragOverData;
33147 overEvent.tree = this.tree;
33148 overEvent.target = targetNode;
33149 overEvent.data = data;
33150 overEvent.point = pt;
33151 overEvent.source = dd;
33152 overEvent.rawEvent = e;
33153 overEvent.dropNode = dropNode;
33154 overEvent.cancel = false;
33155 var result = this.tree.fireEvent("nodedragover", overEvent);
33156 return overEvent.cancel === false && result !== false;
33159 getDropPoint : function(e, n, dd){
33162 return tn.allowChildren !== false ? "append" : false; // always append for root
33164 var dragEl = n.ddel;
33165 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33166 var y = Roo.lib.Event.getPageY(e);
33167 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33169 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33170 var noAppend = tn.allowChildren === false;
33171 if(this.appendOnly || tn.parentNode.allowChildren === false){
33172 return noAppend ? false : "append";
33174 var noBelow = false;
33175 if(!this.allowParentInsert){
33176 noBelow = tn.hasChildNodes() && tn.isExpanded();
33178 var q = (b - t) / (noAppend ? 2 : 3);
33179 if(y >= t && y < (t + q)){
33181 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33188 onNodeEnter : function(n, dd, e, data){
33189 this.cancelExpand();
33192 onNodeOver : function(n, dd, e, data){
33193 var pt = this.getDropPoint(e, n, dd);
33196 // auto node expand check
33197 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33198 this.queueExpand(node);
33199 }else if(pt != "append"){
33200 this.cancelExpand();
33203 // set the insert point style on the target node
33204 var returnCls = this.dropNotAllowed;
33205 if(this.isValidDropPoint(n, pt, dd, e, data)){
33210 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33211 cls = "x-tree-drag-insert-above";
33212 }else if(pt == "below"){
33213 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33214 cls = "x-tree-drag-insert-below";
33216 returnCls = "x-tree-drop-ok-append";
33217 cls = "x-tree-drag-append";
33219 if(this.lastInsertClass != cls){
33220 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33221 this.lastInsertClass = cls;
33228 onNodeOut : function(n, dd, e, data){
33229 this.cancelExpand();
33230 this.removeDropIndicators(n);
33233 onNodeDrop : function(n, dd, e, data){
33234 var point = this.getDropPoint(e, n, dd);
33235 var targetNode = n.node;
33236 targetNode.ui.startDrop();
33237 if(!this.isValidDropPoint(n, point, dd, e, data)){
33238 targetNode.ui.endDrop();
33241 // first try to find the drop node
33242 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33245 target: targetNode,
33250 dropNode: dropNode,
33253 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33254 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33255 targetNode.ui.endDrop();
33258 // allow target changing
33259 targetNode = dropEvent.target;
33260 if(point == "append" && !targetNode.isExpanded()){
33261 targetNode.expand(false, null, function(){
33262 this.completeDrop(dropEvent);
33263 }.createDelegate(this));
33265 this.completeDrop(dropEvent);
33270 completeDrop : function(de){
33271 var ns = de.dropNode, p = de.point, t = de.target;
33272 if(!(ns instanceof Array)){
33276 for(var i = 0, len = ns.length; i < len; i++){
33279 t.parentNode.insertBefore(n, t);
33280 }else if(p == "below"){
33281 t.parentNode.insertBefore(n, t.nextSibling);
33287 if(this.tree.hlDrop){
33291 this.tree.fireEvent("nodedrop", de);
33294 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33295 if(this.tree.hlDrop){
33296 dropNode.ui.focus();
33297 dropNode.ui.highlight();
33299 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33302 getTree : function(){
33306 removeDropIndicators : function(n){
33309 Roo.fly(el).removeClass([
33310 "x-tree-drag-insert-above",
33311 "x-tree-drag-insert-below",
33312 "x-tree-drag-append"]);
33313 this.lastInsertClass = "_noclass";
33317 beforeDragDrop : function(target, e, id){
33318 this.cancelExpand();
33322 afterRepair : function(data){
33323 if(data && Roo.enableFx){
33324 data.node.ui.highlight();
33333 * Ext JS Library 1.1.1
33334 * Copyright(c) 2006-2007, Ext JS, LLC.
33336 * Originally Released Under LGPL - original licence link has changed is not relivant.
33339 * <script type="text/javascript">
33343 if(Roo.dd.DragZone){
33344 Roo.tree.TreeDragZone = function(tree, config){
33345 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33349 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33350 ddGroup : "TreeDD",
33352 onBeforeDrag : function(data, e){
33354 return n && n.draggable && !n.disabled;
33357 onInitDrag : function(e){
33358 var data = this.dragData;
33359 this.tree.getSelectionModel().select(data.node);
33360 this.proxy.update("");
33361 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33362 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33365 getRepairXY : function(e, data){
33366 return data.node.ui.getDDRepairXY();
33369 onEndDrag : function(data, e){
33370 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33373 onValidDrop : function(dd, e, id){
33374 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33378 beforeInvalidDrop : function(e, id){
33379 // this scrolls the original position back into view
33380 var sm = this.tree.getSelectionModel();
33381 sm.clearSelections();
33382 sm.select(this.dragData.node);
33387 * Ext JS Library 1.1.1
33388 * Copyright(c) 2006-2007, Ext JS, LLC.
33390 * Originally Released Under LGPL - original licence link has changed is not relivant.
33393 * <script type="text/javascript">
33396 * @class Roo.tree.TreeEditor
33397 * @extends Roo.Editor
33398 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33399 * as the editor field.
33401 * @param {TreePanel} tree
33402 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33404 Roo.tree.TreeEditor = function(tree, config){
33405 config = config || {};
33406 var field = config.events ? config : new Roo.form.TextField(config);
33407 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33411 tree.on('beforeclick', this.beforeNodeClick, this);
33412 tree.getTreeEl().on('mousedown', this.hide, this);
33413 this.on('complete', this.updateNode, this);
33414 this.on('beforestartedit', this.fitToTree, this);
33415 this.on('startedit', this.bindScroll, this, {delay:10});
33416 this.on('specialkey', this.onSpecialKey, this);
33419 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33421 * @cfg {String} alignment
33422 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33428 * @cfg {Boolean} hideEl
33429 * True to hide the bound element while the editor is displayed (defaults to false)
33433 * @cfg {String} cls
33434 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33436 cls: "x-small-editor x-tree-editor",
33438 * @cfg {Boolean} shim
33439 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33445 * @cfg {Number} maxWidth
33446 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33447 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33448 * scroll and client offsets into account prior to each edit.
33455 fitToTree : function(ed, el){
33456 var td = this.tree.getTreeEl().dom, nd = el.dom;
33457 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33458 td.scrollLeft = nd.offsetLeft;
33462 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33463 this.setSize(w, '');
33467 triggerEdit : function(node){
33468 this.completeEdit();
33469 this.editNode = node;
33470 this.startEdit(node.ui.textNode, node.text);
33474 bindScroll : function(){
33475 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33479 beforeNodeClick : function(node, e){
33480 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33481 this.lastClick = new Date();
33482 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33484 this.triggerEdit(node);
33490 updateNode : function(ed, value){
33491 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33492 this.editNode.setText(value);
33496 onHide : function(){
33497 Roo.tree.TreeEditor.superclass.onHide.call(this);
33499 this.editNode.ui.focus();
33504 onSpecialKey : function(field, e){
33505 var k = e.getKey();
33509 }else if(k == e.ENTER && !e.hasModifier()){
33511 this.completeEdit();
33514 });//<Script type="text/javascript">
33517 * Ext JS Library 1.1.1
33518 * Copyright(c) 2006-2007, Ext JS, LLC.
33520 * Originally Released Under LGPL - original licence link has changed is not relivant.
33523 * <script type="text/javascript">
33527 * Not documented??? - probably should be...
33530 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33531 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33533 renderElements : function(n, a, targetNode, bulkRender){
33534 //consel.log("renderElements?");
33535 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33537 var t = n.getOwnerTree();
33538 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33540 var cols = t.columns;
33541 var bw = t.borderWidth;
33543 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33544 var cb = typeof a.checked == "boolean";
33545 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33546 var colcls = 'x-t-' + tid + '-c0';
33548 '<li class="x-tree-node">',
33551 '<div class="x-tree-node-el ', a.cls,'">',
33553 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33556 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33557 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33558 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33559 (a.icon ? ' x-tree-node-inline-icon' : ''),
33560 (a.iconCls ? ' '+a.iconCls : ''),
33561 '" unselectable="on" />',
33562 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33563 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33565 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33566 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33567 '<span unselectable="on" qtip="' + tx + '">',
33571 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33572 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33574 for(var i = 1, len = cols.length; i < len; i++){
33576 colcls = 'x-t-' + tid + '-c' +i;
33577 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33578 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33579 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33585 '<div class="x-clear"></div></div>',
33586 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33589 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33590 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33591 n.nextSibling.ui.getEl(), buf.join(""));
33593 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33595 var el = this.wrap.firstChild;
33597 this.elNode = el.firstChild;
33598 this.ranchor = el.childNodes[1];
33599 this.ctNode = this.wrap.childNodes[1];
33600 var cs = el.firstChild.childNodes;
33601 this.indentNode = cs[0];
33602 this.ecNode = cs[1];
33603 this.iconNode = cs[2];
33606 this.checkbox = cs[3];
33609 this.anchor = cs[index];
33611 this.textNode = cs[index].firstChild;
33613 //el.on("click", this.onClick, this);
33614 //el.on("dblclick", this.onDblClick, this);
33617 // console.log(this);
33619 initEvents : function(){
33620 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33623 var a = this.ranchor;
33625 var el = Roo.get(a);
33627 if(Roo.isOpera){ // opera render bug ignores the CSS
33628 el.setStyle("text-decoration", "none");
33631 el.on("click", this.onClick, this);
33632 el.on("dblclick", this.onDblClick, this);
33633 el.on("contextmenu", this.onContextMenu, this);
33637 /*onSelectedChange : function(state){
33640 this.addClass("x-tree-selected");
33643 this.removeClass("x-tree-selected");
33646 addClass : function(cls){
33648 Roo.fly(this.elRow).addClass(cls);
33654 removeClass : function(cls){
33656 Roo.fly(this.elRow).removeClass(cls);
33662 });//<Script type="text/javascript">
33666 * Ext JS Library 1.1.1
33667 * Copyright(c) 2006-2007, Ext JS, LLC.
33669 * Originally Released Under LGPL - original licence link has changed is not relivant.
33672 * <script type="text/javascript">
33677 * @class Roo.tree.ColumnTree
33678 * @extends Roo.data.TreePanel
33679 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33680 * @cfg {int} borderWidth compined right/left border allowance
33682 * @param {String/HTMLElement/Element} el The container element
33683 * @param {Object} config
33685 Roo.tree.ColumnTree = function(el, config)
33687 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33691 * Fire this event on a container when it resizes
33692 * @param {int} w Width
33693 * @param {int} h Height
33697 this.on('resize', this.onResize, this);
33700 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33704 borderWidth: Roo.isBorderBox ? 0 : 2,
33707 render : function(){
33708 // add the header.....
33710 Roo.tree.ColumnTree.superclass.render.apply(this);
33712 this.el.addClass('x-column-tree');
33714 this.headers = this.el.createChild(
33715 {cls:'x-tree-headers'},this.innerCt.dom);
33717 var cols = this.columns, c;
33718 var totalWidth = 0;
33720 var len = cols.length;
33721 for(var i = 0; i < len; i++){
33723 totalWidth += c.width;
33724 this.headEls.push(this.headers.createChild({
33725 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33727 cls:'x-tree-hd-text',
33730 style:'width:'+(c.width-this.borderWidth)+'px;'
33733 this.headers.createChild({cls:'x-clear'});
33734 // prevent floats from wrapping when clipped
33735 this.headers.setWidth(totalWidth);
33736 //this.innerCt.setWidth(totalWidth);
33737 this.innerCt.setStyle({ overflow: 'auto' });
33738 this.onResize(this.width, this.height);
33742 onResize : function(w,h)
33747 this.innerCt.setWidth(this.width);
33748 this.innerCt.setHeight(this.height-20);
33751 var cols = this.columns, c;
33752 var totalWidth = 0;
33754 var len = cols.length;
33755 for(var i = 0; i < len; i++){
33757 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33758 // it's the expander..
33759 expEl = this.headEls[i];
33762 totalWidth += c.width;
33766 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33768 this.headers.setWidth(w-20);
33777 * Ext JS Library 1.1.1
33778 * Copyright(c) 2006-2007, Ext JS, LLC.
33780 * Originally Released Under LGPL - original licence link has changed is not relivant.
33783 * <script type="text/javascript">
33787 * @class Roo.menu.Menu
33788 * @extends Roo.util.Observable
33789 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33790 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33792 * Creates a new Menu
33793 * @param {Object} config Configuration options
33795 Roo.menu.Menu = function(config){
33796 Roo.apply(this, config);
33797 this.id = this.id || Roo.id();
33800 * @event beforeshow
33801 * Fires before this menu is displayed
33802 * @param {Roo.menu.Menu} this
33806 * @event beforehide
33807 * Fires before this menu is hidden
33808 * @param {Roo.menu.Menu} this
33813 * Fires after this menu is displayed
33814 * @param {Roo.menu.Menu} this
33819 * Fires after this menu is hidden
33820 * @param {Roo.menu.Menu} this
33825 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33826 * @param {Roo.menu.Menu} this
33827 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33828 * @param {Roo.EventObject} e
33833 * Fires when the mouse is hovering over this menu
33834 * @param {Roo.menu.Menu} this
33835 * @param {Roo.EventObject} e
33836 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33841 * Fires when the mouse exits this menu
33842 * @param {Roo.menu.Menu} this
33843 * @param {Roo.EventObject} e
33844 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33849 * Fires when a menu item contained in this menu is clicked
33850 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33851 * @param {Roo.EventObject} e
33855 if (this.registerMenu) {
33856 Roo.menu.MenuMgr.register(this);
33859 var mis = this.items;
33860 this.items = new Roo.util.MixedCollection();
33862 this.add.apply(this, mis);
33866 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33868 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33872 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33873 * for bottom-right shadow (defaults to "sides")
33877 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33878 * this menu (defaults to "tl-tr?")
33880 subMenuAlign : "tl-tr?",
33882 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33883 * relative to its element of origin (defaults to "tl-bl?")
33885 defaultAlign : "tl-bl?",
33887 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33889 allowOtherMenus : false,
33891 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33893 registerMenu : true,
33898 render : function(){
33902 var el = this.el = new Roo.Layer({
33904 shadow:this.shadow,
33906 parentEl: this.parentEl || document.body,
33910 this.keyNav = new Roo.menu.MenuNav(this);
33913 el.addClass("x-menu-plain");
33916 el.addClass(this.cls);
33918 // generic focus element
33919 this.focusEl = el.createChild({
33920 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33922 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33923 ul.on("click", this.onClick, this);
33924 ul.on("mouseover", this.onMouseOver, this);
33925 ul.on("mouseout", this.onMouseOut, this);
33926 this.items.each(function(item){
33927 var li = document.createElement("li");
33928 li.className = "x-menu-list-item";
33929 ul.dom.appendChild(li);
33930 item.render(li, this);
33937 autoWidth : function(){
33938 var el = this.el, ul = this.ul;
33942 var w = this.width;
33945 }else if(Roo.isIE){
33946 el.setWidth(this.minWidth);
33947 var t = el.dom.offsetWidth; // force recalc
33948 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33953 delayAutoWidth : function(){
33956 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33958 this.awTask.delay(20);
33963 findTargetItem : function(e){
33964 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33965 if(t && t.menuItemId){
33966 return this.items.get(t.menuItemId);
33971 onClick : function(e){
33973 if(t = this.findTargetItem(e)){
33975 this.fireEvent("click", this, t, e);
33980 setActiveItem : function(item, autoExpand){
33981 if(item != this.activeItem){
33982 if(this.activeItem){
33983 this.activeItem.deactivate();
33985 this.activeItem = item;
33986 item.activate(autoExpand);
33987 }else if(autoExpand){
33993 tryActivate : function(start, step){
33994 var items = this.items;
33995 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33996 var item = items.get(i);
33997 if(!item.disabled && item.canActivate){
33998 this.setActiveItem(item, false);
34006 onMouseOver : function(e){
34008 if(t = this.findTargetItem(e)){
34009 if(t.canActivate && !t.disabled){
34010 this.setActiveItem(t, true);
34013 this.fireEvent("mouseover", this, e, t);
34017 onMouseOut : function(e){
34019 if(t = this.findTargetItem(e)){
34020 if(t == this.activeItem && t.shouldDeactivate(e)){
34021 this.activeItem.deactivate();
34022 delete this.activeItem;
34025 this.fireEvent("mouseout", this, e, t);
34029 * Read-only. Returns true if the menu is currently displayed, else false.
34032 isVisible : function(){
34033 return this.el && !this.hidden;
34037 * Displays this menu relative to another element
34038 * @param {String/HTMLElement/Roo.Element} element The element to align to
34039 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34040 * the element (defaults to this.defaultAlign)
34041 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34043 show : function(el, pos, parentMenu){
34044 this.parentMenu = parentMenu;
34048 this.fireEvent("beforeshow", this);
34049 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34053 * Displays this menu at a specific xy position
34054 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34055 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34057 showAt : function(xy, parentMenu, /* private: */_e){
34058 this.parentMenu = parentMenu;
34063 this.fireEvent("beforeshow", this);
34064 xy = this.el.adjustForConstraints(xy);
34068 this.hidden = false;
34070 this.fireEvent("show", this);
34073 focus : function(){
34075 this.doFocus.defer(50, this);
34079 doFocus : function(){
34081 this.focusEl.focus();
34086 * Hides this menu and optionally all parent menus
34087 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34089 hide : function(deep){
34090 if(this.el && this.isVisible()){
34091 this.fireEvent("beforehide", this);
34092 if(this.activeItem){
34093 this.activeItem.deactivate();
34094 this.activeItem = null;
34097 this.hidden = true;
34098 this.fireEvent("hide", this);
34100 if(deep === true && this.parentMenu){
34101 this.parentMenu.hide(true);
34106 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34107 * Any of the following are valid:
34109 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34110 * <li>An HTMLElement object which will be converted to a menu item</li>
34111 * <li>A menu item config object that will be created as a new menu item</li>
34112 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34113 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34118 var menu = new Roo.menu.Menu();
34120 // Create a menu item to add by reference
34121 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34123 // Add a bunch of items at once using different methods.
34124 // Only the last item added will be returned.
34125 var item = menu.add(
34126 menuItem, // add existing item by ref
34127 'Dynamic Item', // new TextItem
34128 '-', // new separator
34129 { text: 'Config Item' } // new item by config
34132 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34133 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34136 var a = arguments, l = a.length, item;
34137 for(var i = 0; i < l; i++){
34139 if ((typeof(el) == "object") && el.xtype && el.xns) {
34140 el = Roo.factory(el, Roo.menu);
34143 if(el.render){ // some kind of Item
34144 item = this.addItem(el);
34145 }else if(typeof el == "string"){ // string
34146 if(el == "separator" || el == "-"){
34147 item = this.addSeparator();
34149 item = this.addText(el);
34151 }else if(el.tagName || el.el){ // element
34152 item = this.addElement(el);
34153 }else if(typeof el == "object"){ // must be menu item config?
34154 item = this.addMenuItem(el);
34161 * Returns this menu's underlying {@link Roo.Element} object
34162 * @return {Roo.Element} The element
34164 getEl : function(){
34172 * Adds a separator bar to the menu
34173 * @return {Roo.menu.Item} The menu item that was added
34175 addSeparator : function(){
34176 return this.addItem(new Roo.menu.Separator());
34180 * Adds an {@link Roo.Element} object to the menu
34181 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34182 * @return {Roo.menu.Item} The menu item that was added
34184 addElement : function(el){
34185 return this.addItem(new Roo.menu.BaseItem(el));
34189 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34190 * @param {Roo.menu.Item} item The menu item to add
34191 * @return {Roo.menu.Item} The menu item that was added
34193 addItem : function(item){
34194 this.items.add(item);
34196 var li = document.createElement("li");
34197 li.className = "x-menu-list-item";
34198 this.ul.dom.appendChild(li);
34199 item.render(li, this);
34200 this.delayAutoWidth();
34206 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34207 * @param {Object} config A MenuItem config object
34208 * @return {Roo.menu.Item} The menu item that was added
34210 addMenuItem : function(config){
34211 if(!(config instanceof Roo.menu.Item)){
34212 if(typeof config.checked == "boolean"){ // must be check menu item config?
34213 config = new Roo.menu.CheckItem(config);
34215 config = new Roo.menu.Item(config);
34218 return this.addItem(config);
34222 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34223 * @param {String} text The text to display in the menu item
34224 * @return {Roo.menu.Item} The menu item that was added
34226 addText : function(text){
34227 return this.addItem(new Roo.menu.TextItem({ text : text }));
34231 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34232 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34233 * @param {Roo.menu.Item} item The menu item to add
34234 * @return {Roo.menu.Item} The menu item that was added
34236 insert : function(index, item){
34237 this.items.insert(index, item);
34239 var li = document.createElement("li");
34240 li.className = "x-menu-list-item";
34241 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34242 item.render(li, this);
34243 this.delayAutoWidth();
34249 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34250 * @param {Roo.menu.Item} item The menu item to remove
34252 remove : function(item){
34253 this.items.removeKey(item.id);
34258 * Removes and destroys all items in the menu
34260 removeAll : function(){
34262 while(f = this.items.first()){
34268 // MenuNav is a private utility class used internally by the Menu
34269 Roo.menu.MenuNav = function(menu){
34270 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34271 this.scope = this.menu = menu;
34274 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34275 doRelay : function(e, h){
34276 var k = e.getKey();
34277 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34278 this.menu.tryActivate(0, 1);
34281 return h.call(this.scope || this, e, this.menu);
34284 up : function(e, m){
34285 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34286 m.tryActivate(m.items.length-1, -1);
34290 down : function(e, m){
34291 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34292 m.tryActivate(0, 1);
34296 right : function(e, m){
34298 m.activeItem.expandMenu(true);
34302 left : function(e, m){
34304 if(m.parentMenu && m.parentMenu.activeItem){
34305 m.parentMenu.activeItem.activate();
34309 enter : function(e, m){
34311 e.stopPropagation();
34312 m.activeItem.onClick(e);
34313 m.fireEvent("click", this, m.activeItem);
34319 * Ext JS Library 1.1.1
34320 * Copyright(c) 2006-2007, Ext JS, LLC.
34322 * Originally Released Under LGPL - original licence link has changed is not relivant.
34325 * <script type="text/javascript">
34329 * @class Roo.menu.MenuMgr
34330 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34333 Roo.menu.MenuMgr = function(){
34334 var menus, active, groups = {}, attached = false, lastShow = new Date();
34336 // private - called when first menu is created
34339 active = new Roo.util.MixedCollection();
34340 Roo.get(document).addKeyListener(27, function(){
34341 if(active.length > 0){
34348 function hideAll(){
34349 if(active && active.length > 0){
34350 var c = active.clone();
34351 c.each(function(m){
34358 function onHide(m){
34360 if(active.length < 1){
34361 Roo.get(document).un("mousedown", onMouseDown);
34367 function onShow(m){
34368 var last = active.last();
34369 lastShow = new Date();
34372 Roo.get(document).on("mousedown", onMouseDown);
34376 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34377 m.parentMenu.activeChild = m;
34378 }else if(last && last.isVisible()){
34379 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34384 function onBeforeHide(m){
34386 m.activeChild.hide();
34388 if(m.autoHideTimer){
34389 clearTimeout(m.autoHideTimer);
34390 delete m.autoHideTimer;
34395 function onBeforeShow(m){
34396 var pm = m.parentMenu;
34397 if(!pm && !m.allowOtherMenus){
34399 }else if(pm && pm.activeChild && active != m){
34400 pm.activeChild.hide();
34405 function onMouseDown(e){
34406 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34412 function onBeforeCheck(mi, state){
34414 var g = groups[mi.group];
34415 for(var i = 0, l = g.length; i < l; i++){
34417 g[i].setChecked(false);
34426 * Hides all menus that are currently visible
34428 hideAll : function(){
34433 register : function(menu){
34437 menus[menu.id] = menu;
34438 menu.on("beforehide", onBeforeHide);
34439 menu.on("hide", onHide);
34440 menu.on("beforeshow", onBeforeShow);
34441 menu.on("show", onShow);
34442 var g = menu.group;
34443 if(g && menu.events["checkchange"]){
34447 groups[g].push(menu);
34448 menu.on("checkchange", onCheck);
34453 * Returns a {@link Roo.menu.Menu} object
34454 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34455 * be used to generate and return a new Menu instance.
34457 get : function(menu){
34458 if(typeof menu == "string"){ // menu id
34459 return menus[menu];
34460 }else if(menu.events){ // menu instance
34462 }else if(typeof menu.length == 'number'){ // array of menu items?
34463 return new Roo.menu.Menu({items:menu});
34464 }else{ // otherwise, must be a config
34465 return new Roo.menu.Menu(menu);
34470 unregister : function(menu){
34471 delete menus[menu.id];
34472 menu.un("beforehide", onBeforeHide);
34473 menu.un("hide", onHide);
34474 menu.un("beforeshow", onBeforeShow);
34475 menu.un("show", onShow);
34476 var g = menu.group;
34477 if(g && menu.events["checkchange"]){
34478 groups[g].remove(menu);
34479 menu.un("checkchange", onCheck);
34484 registerCheckable : function(menuItem){
34485 var g = menuItem.group;
34490 groups[g].push(menuItem);
34491 menuItem.on("beforecheckchange", onBeforeCheck);
34496 unregisterCheckable : function(menuItem){
34497 var g = menuItem.group;
34499 groups[g].remove(menuItem);
34500 menuItem.un("beforecheckchange", onBeforeCheck);
34506 * Ext JS Library 1.1.1
34507 * Copyright(c) 2006-2007, Ext JS, LLC.
34509 * Originally Released Under LGPL - original licence link has changed is not relivant.
34512 * <script type="text/javascript">
34517 * @class Roo.menu.BaseItem
34518 * @extends Roo.Component
34519 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34520 * management and base configuration options shared by all menu components.
34522 * Creates a new BaseItem
34523 * @param {Object} config Configuration options
34525 Roo.menu.BaseItem = function(config){
34526 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34531 * Fires when this item is clicked
34532 * @param {Roo.menu.BaseItem} this
34533 * @param {Roo.EventObject} e
34538 * Fires when this item is activated
34539 * @param {Roo.menu.BaseItem} this
34543 * @event deactivate
34544 * Fires when this item is deactivated
34545 * @param {Roo.menu.BaseItem} this
34551 this.on("click", this.handler, this.scope, true);
34555 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34557 * @cfg {Function} handler
34558 * A function that will handle the click event of this menu item (defaults to undefined)
34561 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34563 canActivate : false,
34565 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34567 activeClass : "x-menu-item-active",
34569 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34571 hideOnClick : true,
34573 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34578 ctype: "Roo.menu.BaseItem",
34581 actionMode : "container",
34584 render : function(container, parentMenu){
34585 this.parentMenu = parentMenu;
34586 Roo.menu.BaseItem.superclass.render.call(this, container);
34587 this.container.menuItemId = this.id;
34591 onRender : function(container, position){
34592 this.el = Roo.get(this.el);
34593 container.dom.appendChild(this.el.dom);
34597 onClick : function(e){
34598 if(!this.disabled && this.fireEvent("click", this, e) !== false
34599 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34600 this.handleClick(e);
34607 activate : function(){
34611 var li = this.container;
34612 li.addClass(this.activeClass);
34613 this.region = li.getRegion().adjust(2, 2, -2, -2);
34614 this.fireEvent("activate", this);
34619 deactivate : function(){
34620 this.container.removeClass(this.activeClass);
34621 this.fireEvent("deactivate", this);
34625 shouldDeactivate : function(e){
34626 return !this.region || !this.region.contains(e.getPoint());
34630 handleClick : function(e){
34631 if(this.hideOnClick){
34632 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34637 expandMenu : function(autoActivate){
34642 hideMenu : function(){
34647 * Ext JS Library 1.1.1
34648 * Copyright(c) 2006-2007, Ext JS, LLC.
34650 * Originally Released Under LGPL - original licence link has changed is not relivant.
34653 * <script type="text/javascript">
34657 * @class Roo.menu.Adapter
34658 * @extends Roo.menu.BaseItem
34659 * 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.
34660 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34662 * Creates a new Adapter
34663 * @param {Object} config Configuration options
34665 Roo.menu.Adapter = function(component, config){
34666 Roo.menu.Adapter.superclass.constructor.call(this, config);
34667 this.component = component;
34669 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34671 canActivate : true,
34674 onRender : function(container, position){
34675 this.component.render(container);
34676 this.el = this.component.getEl();
34680 activate : function(){
34684 this.component.focus();
34685 this.fireEvent("activate", this);
34690 deactivate : function(){
34691 this.fireEvent("deactivate", this);
34695 disable : function(){
34696 this.component.disable();
34697 Roo.menu.Adapter.superclass.disable.call(this);
34701 enable : function(){
34702 this.component.enable();
34703 Roo.menu.Adapter.superclass.enable.call(this);
34707 * Ext JS Library 1.1.1
34708 * Copyright(c) 2006-2007, Ext JS, LLC.
34710 * Originally Released Under LGPL - original licence link has changed is not relivant.
34713 * <script type="text/javascript">
34717 * @class Roo.menu.TextItem
34718 * @extends Roo.menu.BaseItem
34719 * Adds a static text string to a menu, usually used as either a heading or group separator.
34720 * Note: old style constructor with text is still supported.
34723 * Creates a new TextItem
34724 * @param {Object} cfg Configuration
34726 Roo.menu.TextItem = function(cfg){
34727 if (typeof(cfg) == 'string') {
34730 Roo.apply(this,cfg);
34733 Roo.menu.TextItem.superclass.constructor.call(this);
34736 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34738 * @cfg {Boolean} text Text to show on item.
34743 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34745 hideOnClick : false,
34747 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34749 itemCls : "x-menu-text",
34752 onRender : function(){
34753 var s = document.createElement("span");
34754 s.className = this.itemCls;
34755 s.innerHTML = this.text;
34757 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34761 * Ext JS Library 1.1.1
34762 * Copyright(c) 2006-2007, Ext JS, LLC.
34764 * Originally Released Under LGPL - original licence link has changed is not relivant.
34767 * <script type="text/javascript">
34771 * @class Roo.menu.Separator
34772 * @extends Roo.menu.BaseItem
34773 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34774 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34776 * @param {Object} config Configuration options
34778 Roo.menu.Separator = function(config){
34779 Roo.menu.Separator.superclass.constructor.call(this, config);
34782 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34784 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34786 itemCls : "x-menu-sep",
34788 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34790 hideOnClick : false,
34793 onRender : function(li){
34794 var s = document.createElement("span");
34795 s.className = this.itemCls;
34796 s.innerHTML = " ";
34798 li.addClass("x-menu-sep-li");
34799 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34803 * Ext JS Library 1.1.1
34804 * Copyright(c) 2006-2007, Ext JS, LLC.
34806 * Originally Released Under LGPL - original licence link has changed is not relivant.
34809 * <script type="text/javascript">
34812 * @class Roo.menu.Item
34813 * @extends Roo.menu.BaseItem
34814 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34815 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34816 * activation and click handling.
34818 * Creates a new Item
34819 * @param {Object} config Configuration options
34821 Roo.menu.Item = function(config){
34822 Roo.menu.Item.superclass.constructor.call(this, config);
34824 this.menu = Roo.menu.MenuMgr.get(this.menu);
34827 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34830 * @cfg {String} text
34831 * The text to show on the menu item.
34835 * @cfg {String} HTML to render in menu
34836 * The text to show on the menu item (HTML version).
34840 * @cfg {String} icon
34841 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34845 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34847 itemCls : "x-menu-item",
34849 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34851 canActivate : true,
34853 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34856 // doc'd in BaseItem
34860 ctype: "Roo.menu.Item",
34863 onRender : function(container, position){
34864 var el = document.createElement("a");
34865 el.hideFocus = true;
34866 el.unselectable = "on";
34867 el.href = this.href || "#";
34868 if(this.hrefTarget){
34869 el.target = this.hrefTarget;
34871 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34873 var html = this.html.length ? this.html : String.format('{0}',this.text);
34875 el.innerHTML = String.format(
34876 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34877 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34879 Roo.menu.Item.superclass.onRender.call(this, container, position);
34883 * Sets the text to display in this menu item
34884 * @param {String} text The text to display
34885 * @param {Boolean} isHTML true to indicate text is pure html.
34887 setText : function(text, isHTML){
34895 var html = this.html.length ? this.html : String.format('{0}',this.text);
34897 this.el.update(String.format(
34898 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34899 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34900 this.parentMenu.autoWidth();
34905 handleClick : function(e){
34906 if(!this.href){ // if no link defined, stop the event automatically
34909 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34913 activate : function(autoExpand){
34914 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34924 shouldDeactivate : function(e){
34925 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34926 if(this.menu && this.menu.isVisible()){
34927 return !this.menu.getEl().getRegion().contains(e.getPoint());
34935 deactivate : function(){
34936 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34941 expandMenu : function(autoActivate){
34942 if(!this.disabled && this.menu){
34943 clearTimeout(this.hideTimer);
34944 delete this.hideTimer;
34945 if(!this.menu.isVisible() && !this.showTimer){
34946 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34947 }else if (this.menu.isVisible() && autoActivate){
34948 this.menu.tryActivate(0, 1);
34954 deferExpand : function(autoActivate){
34955 delete this.showTimer;
34956 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34958 this.menu.tryActivate(0, 1);
34963 hideMenu : function(){
34964 clearTimeout(this.showTimer);
34965 delete this.showTimer;
34966 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34967 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34972 deferHide : function(){
34973 delete this.hideTimer;
34978 * Ext JS Library 1.1.1
34979 * Copyright(c) 2006-2007, Ext JS, LLC.
34981 * Originally Released Under LGPL - original licence link has changed is not relivant.
34984 * <script type="text/javascript">
34988 * @class Roo.menu.CheckItem
34989 * @extends Roo.menu.Item
34990 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34992 * Creates a new CheckItem
34993 * @param {Object} config Configuration options
34995 Roo.menu.CheckItem = function(config){
34996 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34999 * @event beforecheckchange
35000 * Fires before the checked value is set, providing an opportunity to cancel if needed
35001 * @param {Roo.menu.CheckItem} this
35002 * @param {Boolean} checked The new checked value that will be set
35004 "beforecheckchange" : true,
35006 * @event checkchange
35007 * Fires after the checked value has been set
35008 * @param {Roo.menu.CheckItem} this
35009 * @param {Boolean} checked The checked value that was set
35011 "checkchange" : true
35013 if(this.checkHandler){
35014 this.on('checkchange', this.checkHandler, this.scope);
35017 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35019 * @cfg {String} group
35020 * All check items with the same group name will automatically be grouped into a single-select
35021 * radio button group (defaults to '')
35024 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35026 itemCls : "x-menu-item x-menu-check-item",
35028 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35030 groupClass : "x-menu-group-item",
35033 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35034 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35035 * initialized with checked = true will be rendered as checked.
35040 ctype: "Roo.menu.CheckItem",
35043 onRender : function(c){
35044 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35046 this.el.addClass(this.groupClass);
35048 Roo.menu.MenuMgr.registerCheckable(this);
35050 this.checked = false;
35051 this.setChecked(true, true);
35056 destroy : function(){
35058 Roo.menu.MenuMgr.unregisterCheckable(this);
35060 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35064 * Set the checked state of this item
35065 * @param {Boolean} checked The new checked value
35066 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35068 setChecked : function(state, suppressEvent){
35069 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35070 if(this.container){
35071 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35073 this.checked = state;
35074 if(suppressEvent !== true){
35075 this.fireEvent("checkchange", this, state);
35081 handleClick : function(e){
35082 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35083 this.setChecked(!this.checked);
35085 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35089 * Ext JS Library 1.1.1
35090 * Copyright(c) 2006-2007, Ext JS, LLC.
35092 * Originally Released Under LGPL - original licence link has changed is not relivant.
35095 * <script type="text/javascript">
35099 * @class Roo.menu.DateItem
35100 * @extends Roo.menu.Adapter
35101 * A menu item that wraps the {@link Roo.DatPicker} component.
35103 * Creates a new DateItem
35104 * @param {Object} config Configuration options
35106 Roo.menu.DateItem = function(config){
35107 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35108 /** The Roo.DatePicker object @type Roo.DatePicker */
35109 this.picker = this.component;
35110 this.addEvents({select: true});
35112 this.picker.on("render", function(picker){
35113 picker.getEl().swallowEvent("click");
35114 picker.container.addClass("x-menu-date-item");
35117 this.picker.on("select", this.onSelect, this);
35120 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35122 onSelect : function(picker, date){
35123 this.fireEvent("select", this, date, picker);
35124 Roo.menu.DateItem.superclass.handleClick.call(this);
35128 * Ext JS Library 1.1.1
35129 * Copyright(c) 2006-2007, Ext JS, LLC.
35131 * Originally Released Under LGPL - original licence link has changed is not relivant.
35134 * <script type="text/javascript">
35138 * @class Roo.menu.ColorItem
35139 * @extends Roo.menu.Adapter
35140 * A menu item that wraps the {@link Roo.ColorPalette} component.
35142 * Creates a new ColorItem
35143 * @param {Object} config Configuration options
35145 Roo.menu.ColorItem = function(config){
35146 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35147 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35148 this.palette = this.component;
35149 this.relayEvents(this.palette, ["select"]);
35150 if(this.selectHandler){
35151 this.on('select', this.selectHandler, this.scope);
35154 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35156 * Ext JS Library 1.1.1
35157 * Copyright(c) 2006-2007, Ext JS, LLC.
35159 * Originally Released Under LGPL - original licence link has changed is not relivant.
35162 * <script type="text/javascript">
35167 * @class Roo.menu.DateMenu
35168 * @extends Roo.menu.Menu
35169 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35171 * Creates a new DateMenu
35172 * @param {Object} config Configuration options
35174 Roo.menu.DateMenu = function(config){
35175 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35177 var di = new Roo.menu.DateItem(config);
35180 * The {@link Roo.DatePicker} instance for this DateMenu
35183 this.picker = di.picker;
35186 * @param {DatePicker} picker
35187 * @param {Date} date
35189 this.relayEvents(di, ["select"]);
35191 this.on('beforeshow', function(){
35193 this.picker.hideMonthPicker(true);
35197 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35201 * Ext JS Library 1.1.1
35202 * Copyright(c) 2006-2007, Ext JS, LLC.
35204 * Originally Released Under LGPL - original licence link has changed is not relivant.
35207 * <script type="text/javascript">
35212 * @class Roo.menu.ColorMenu
35213 * @extends Roo.menu.Menu
35214 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35216 * Creates a new ColorMenu
35217 * @param {Object} config Configuration options
35219 Roo.menu.ColorMenu = function(config){
35220 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35222 var ci = new Roo.menu.ColorItem(config);
35225 * The {@link Roo.ColorPalette} instance for this ColorMenu
35226 * @type ColorPalette
35228 this.palette = ci.palette;
35231 * @param {ColorPalette} palette
35232 * @param {String} color
35234 this.relayEvents(ci, ["select"]);
35236 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35238 * Ext JS Library 1.1.1
35239 * Copyright(c) 2006-2007, Ext JS, LLC.
35241 * Originally Released Under LGPL - original licence link has changed is not relivant.
35244 * <script type="text/javascript">
35248 * @class Roo.form.Field
35249 * @extends Roo.BoxComponent
35250 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35252 * Creates a new Field
35253 * @param {Object} config Configuration options
35255 Roo.form.Field = function(config){
35256 Roo.form.Field.superclass.constructor.call(this, config);
35259 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35261 * @cfg {String} fieldLabel Label to use when rendering a form.
35264 * @cfg {String} qtip Mouse over tip
35268 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35270 invalidClass : "x-form-invalid",
35272 * @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")
35274 invalidText : "The value in this field is invalid",
35276 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35278 focusClass : "x-form-focus",
35280 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35281 automatic validation (defaults to "keyup").
35283 validationEvent : "keyup",
35285 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35287 validateOnBlur : true,
35289 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35291 validationDelay : 250,
35293 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35294 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35296 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35298 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35300 fieldClass : "x-form-field",
35302 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35305 ----------- ----------------------------------------------------------------------
35306 qtip Display a quick tip when the user hovers over the field
35307 title Display a default browser title attribute popup
35308 under Add a block div beneath the field containing the error text
35309 side Add an error icon to the right of the field with a popup on hover
35310 [element id] Add the error text directly to the innerHTML of the specified element
35313 msgTarget : 'qtip',
35315 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35320 * @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.
35325 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35330 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35332 inputType : undefined,
35335 * @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).
35337 tabIndex : undefined,
35340 isFormField : true,
35345 * @property {Roo.Element} fieldEl
35346 * Element Containing the rendered Field (with label etc.)
35349 * @cfg {Mixed} value A value to initialize this field with.
35354 * @cfg {String} name The field's HTML name attribute.
35357 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35361 initComponent : function(){
35362 Roo.form.Field.superclass.initComponent.call(this);
35366 * Fires when this field receives input focus.
35367 * @param {Roo.form.Field} this
35372 * Fires when this field loses input focus.
35373 * @param {Roo.form.Field} this
35377 * @event specialkey
35378 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35379 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35380 * @param {Roo.form.Field} this
35381 * @param {Roo.EventObject} e The event object
35386 * Fires just before the field blurs if the field value has changed.
35387 * @param {Roo.form.Field} this
35388 * @param {Mixed} newValue The new value
35389 * @param {Mixed} oldValue The original value
35394 * Fires after the field has been marked as invalid.
35395 * @param {Roo.form.Field} this
35396 * @param {String} msg The validation message
35401 * Fires after the field has been validated with no errors.
35402 * @param {Roo.form.Field} this
35407 * Fires after the key up
35408 * @param {Roo.form.Field} this
35409 * @param {Roo.EventObject} e The event Object
35416 * Returns the name attribute of the field if available
35417 * @return {String} name The field name
35419 getName: function(){
35420 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35424 onRender : function(ct, position){
35425 Roo.form.Field.superclass.onRender.call(this, ct, position);
35427 var cfg = this.getAutoCreate();
35429 cfg.name = this.name || this.id;
35431 if(this.inputType){
35432 cfg.type = this.inputType;
35434 this.el = ct.createChild(cfg, position);
35436 var type = this.el.dom.type;
35438 if(type == 'password'){
35441 this.el.addClass('x-form-'+type);
35444 this.el.dom.readOnly = true;
35446 if(this.tabIndex !== undefined){
35447 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35450 this.el.addClass([this.fieldClass, this.cls]);
35455 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35456 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35457 * @return {Roo.form.Field} this
35459 applyTo : function(target){
35460 this.allowDomMove = false;
35461 this.el = Roo.get(target);
35462 this.render(this.el.dom.parentNode);
35467 initValue : function(){
35468 if(this.value !== undefined){
35469 this.setValue(this.value);
35470 }else if(this.el.dom.value.length > 0){
35471 this.setValue(this.el.dom.value);
35476 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35478 isDirty : function() {
35479 if(this.disabled) {
35482 return String(this.getValue()) !== String(this.originalValue);
35486 afterRender : function(){
35487 Roo.form.Field.superclass.afterRender.call(this);
35492 fireKey : function(e){
35493 //Roo.log('field ' + e.getKey());
35494 if(e.isNavKeyPress()){
35495 this.fireEvent("specialkey", this, e);
35500 * Resets the current field value to the originally loaded value and clears any validation messages
35502 reset : function(){
35503 this.setValue(this.originalValue);
35504 this.clearInvalid();
35508 initEvents : function(){
35509 // safari killled keypress - so keydown is now used..
35510 this.el.on("keydown" , this.fireKey, this);
35511 this.el.on("focus", this.onFocus, this);
35512 this.el.on("blur", this.onBlur, this);
35513 this.el.relayEvent('keyup', this);
35515 // reference to original value for reset
35516 this.originalValue = this.getValue();
35520 onFocus : function(){
35521 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35522 this.el.addClass(this.focusClass);
35524 if(!this.hasFocus){
35525 this.hasFocus = true;
35526 this.startValue = this.getValue();
35527 this.fireEvent("focus", this);
35531 beforeBlur : Roo.emptyFn,
35534 onBlur : function(){
35536 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35537 this.el.removeClass(this.focusClass);
35539 this.hasFocus = false;
35540 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35543 var v = this.getValue();
35544 if(String(v) !== String(this.startValue)){
35545 this.fireEvent('change', this, v, this.startValue);
35547 this.fireEvent("blur", this);
35551 * Returns whether or not the field value is currently valid
35552 * @param {Boolean} preventMark True to disable marking the field invalid
35553 * @return {Boolean} True if the value is valid, else false
35555 isValid : function(preventMark){
35559 var restore = this.preventMark;
35560 this.preventMark = preventMark === true;
35561 var v = this.validateValue(this.processValue(this.getRawValue()));
35562 this.preventMark = restore;
35567 * Validates the field value
35568 * @return {Boolean} True if the value is valid, else false
35570 validate : function(){
35571 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35572 this.clearInvalid();
35578 processValue : function(value){
35583 // Subclasses should provide the validation implementation by overriding this
35584 validateValue : function(value){
35589 * Mark this field as invalid
35590 * @param {String} msg The validation message
35592 markInvalid : function(msg){
35593 if(!this.rendered || this.preventMark){ // not rendered
35596 this.el.addClass(this.invalidClass);
35597 msg = msg || this.invalidText;
35598 switch(this.msgTarget){
35600 this.el.dom.qtip = msg;
35601 this.el.dom.qclass = 'x-form-invalid-tip';
35602 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35603 Roo.QuickTips.enable();
35607 this.el.dom.title = msg;
35611 var elp = this.el.findParent('.x-form-element', 5, true);
35612 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35613 this.errorEl.setWidth(elp.getWidth(true)-20);
35615 this.errorEl.update(msg);
35616 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35619 if(!this.errorIcon){
35620 var elp = this.el.findParent('.x-form-element', 5, true);
35621 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35623 this.alignErrorIcon();
35624 this.errorIcon.dom.qtip = msg;
35625 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35626 this.errorIcon.show();
35627 this.on('resize', this.alignErrorIcon, this);
35630 var t = Roo.getDom(this.msgTarget);
35632 t.style.display = this.msgDisplay;
35635 this.fireEvent('invalid', this, msg);
35639 alignErrorIcon : function(){
35640 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35644 * Clear any invalid styles/messages for this field
35646 clearInvalid : function(){
35647 if(!this.rendered || this.preventMark){ // not rendered
35650 this.el.removeClass(this.invalidClass);
35651 switch(this.msgTarget){
35653 this.el.dom.qtip = '';
35656 this.el.dom.title = '';
35660 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35664 if(this.errorIcon){
35665 this.errorIcon.dom.qtip = '';
35666 this.errorIcon.hide();
35667 this.un('resize', this.alignErrorIcon, this);
35671 var t = Roo.getDom(this.msgTarget);
35673 t.style.display = 'none';
35676 this.fireEvent('valid', this);
35680 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35681 * @return {Mixed} value The field value
35683 getRawValue : function(){
35684 var v = this.el.getValue();
35685 if(v === this.emptyText){
35692 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35693 * @return {Mixed} value The field value
35695 getValue : function(){
35696 var v = this.el.getValue();
35697 if(v === this.emptyText || v === undefined){
35704 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35705 * @param {Mixed} value The value to set
35707 setRawValue : function(v){
35708 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35712 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35713 * @param {Mixed} value The value to set
35715 setValue : function(v){
35718 this.el.dom.value = (v === null || v === undefined ? '' : v);
35723 adjustSize : function(w, h){
35724 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35725 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35729 adjustWidth : function(tag, w){
35730 tag = tag.toLowerCase();
35731 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35732 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35733 if(tag == 'input'){
35736 if(tag = 'textarea'){
35739 }else if(Roo.isOpera){
35740 if(tag == 'input'){
35743 if(tag = 'textarea'){
35753 // anything other than normal should be considered experimental
35754 Roo.form.Field.msgFx = {
35756 show: function(msgEl, f){
35757 msgEl.setDisplayed('block');
35760 hide : function(msgEl, f){
35761 msgEl.setDisplayed(false).update('');
35766 show: function(msgEl, f){
35767 msgEl.slideIn('t', {stopFx:true});
35770 hide : function(msgEl, f){
35771 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35776 show: function(msgEl, f){
35777 msgEl.fixDisplay();
35778 msgEl.alignTo(f.el, 'tl-tr');
35779 msgEl.slideIn('l', {stopFx:true});
35782 hide : function(msgEl, f){
35783 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35788 * Ext JS Library 1.1.1
35789 * Copyright(c) 2006-2007, Ext JS, LLC.
35791 * Originally Released Under LGPL - original licence link has changed is not relivant.
35794 * <script type="text/javascript">
35799 * @class Roo.form.TextField
35800 * @extends Roo.form.Field
35801 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35802 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35804 * Creates a new TextField
35805 * @param {Object} config Configuration options
35807 Roo.form.TextField = function(config){
35808 Roo.form.TextField.superclass.constructor.call(this, config);
35812 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35813 * according to the default logic, but this event provides a hook for the developer to apply additional
35814 * logic at runtime to resize the field if needed.
35815 * @param {Roo.form.Field} this This text field
35816 * @param {Number} width The new field width
35822 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35824 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35828 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35832 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35836 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35840 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35844 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35846 disableKeyFilter : false,
35848 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35852 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35856 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35858 maxLength : Number.MAX_VALUE,
35860 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35862 minLengthText : "The minimum length for this field is {0}",
35864 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35866 maxLengthText : "The maximum length for this field is {0}",
35868 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35870 selectOnFocus : false,
35872 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35874 blankText : "This field is required",
35876 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35877 * If available, this function will be called only after the basic validators all return true, and will be passed the
35878 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35882 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35883 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35884 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35888 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35892 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35896 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35897 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35899 emptyClass : 'x-form-empty-field',
35902 initEvents : function(){
35903 Roo.form.TextField.superclass.initEvents.call(this);
35904 if(this.validationEvent == 'keyup'){
35905 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35906 this.el.on('keyup', this.filterValidation, this);
35908 else if(this.validationEvent !== false){
35909 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35911 if(this.selectOnFocus || this.emptyText){
35912 this.on("focus", this.preFocus, this);
35913 if(this.emptyText){
35914 this.on('blur', this.postBlur, this);
35915 this.applyEmptyText();
35918 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35919 this.el.on("keypress", this.filterKeys, this);
35922 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35923 this.el.on("click", this.autoSize, this);
35927 processValue : function(value){
35928 if(this.stripCharsRe){
35929 var newValue = value.replace(this.stripCharsRe, '');
35930 if(newValue !== value){
35931 this.setRawValue(newValue);
35938 filterValidation : function(e){
35939 if(!e.isNavKeyPress()){
35940 this.validationTask.delay(this.validationDelay);
35945 onKeyUp : function(e){
35946 if(!e.isNavKeyPress()){
35952 * Resets the current field value to the originally-loaded value and clears any validation messages.
35953 * Also adds emptyText and emptyClass if the original value was blank.
35955 reset : function(){
35956 Roo.form.TextField.superclass.reset.call(this);
35957 this.applyEmptyText();
35960 applyEmptyText : function(){
35961 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35962 this.setRawValue(this.emptyText);
35963 this.el.addClass(this.emptyClass);
35968 preFocus : function(){
35969 if(this.emptyText){
35970 if(this.el.dom.value == this.emptyText){
35971 this.setRawValue('');
35973 this.el.removeClass(this.emptyClass);
35975 if(this.selectOnFocus){
35976 this.el.dom.select();
35981 postBlur : function(){
35982 this.applyEmptyText();
35986 filterKeys : function(e){
35987 var k = e.getKey();
35988 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35991 var c = e.getCharCode(), cc = String.fromCharCode(c);
35992 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35995 if(!this.maskRe.test(cc)){
36000 setValue : function(v){
36001 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36002 this.el.removeClass(this.emptyClass);
36004 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36005 this.applyEmptyText();
36010 * Validates a value according to the field's validation rules and marks the field as invalid
36011 * if the validation fails
36012 * @param {Mixed} value The value to validate
36013 * @return {Boolean} True if the value is valid, else false
36015 validateValue : function(value){
36016 if(value.length < 1 || value === this.emptyText){ // if it's blank
36017 if(this.allowBlank){
36018 this.clearInvalid();
36021 this.markInvalid(this.blankText);
36025 if(value.length < this.minLength){
36026 this.markInvalid(String.format(this.minLengthText, this.minLength));
36029 if(value.length > this.maxLength){
36030 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36034 var vt = Roo.form.VTypes;
36035 if(!vt[this.vtype](value, this)){
36036 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36040 if(typeof this.validator == "function"){
36041 var msg = this.validator(value);
36043 this.markInvalid(msg);
36047 if(this.regex && !this.regex.test(value)){
36048 this.markInvalid(this.regexText);
36055 * Selects text in this field
36056 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36057 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36059 selectText : function(start, end){
36060 var v = this.getRawValue();
36062 start = start === undefined ? 0 : start;
36063 end = end === undefined ? v.length : end;
36064 var d = this.el.dom;
36065 if(d.setSelectionRange){
36066 d.setSelectionRange(start, end);
36067 }else if(d.createTextRange){
36068 var range = d.createTextRange();
36069 range.moveStart("character", start);
36070 range.moveEnd("character", v.length-end);
36077 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36078 * This only takes effect if grow = true, and fires the autosize event.
36080 autoSize : function(){
36081 if(!this.grow || !this.rendered){
36085 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36088 var v = el.dom.value;
36089 var d = document.createElement('div');
36090 d.appendChild(document.createTextNode(v));
36094 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36095 this.el.setWidth(w);
36096 this.fireEvent("autosize", this, w);
36100 * Ext JS Library 1.1.1
36101 * Copyright(c) 2006-2007, Ext JS, LLC.
36103 * Originally Released Under LGPL - original licence link has changed is not relivant.
36106 * <script type="text/javascript">
36110 * @class Roo.form.Hidden
36111 * @extends Roo.form.TextField
36112 * Simple Hidden element used on forms
36114 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36117 * Creates a new Hidden form element.
36118 * @param {Object} config Configuration options
36123 // easy hidden field...
36124 Roo.form.Hidden = function(config){
36125 Roo.form.Hidden.superclass.constructor.call(this, config);
36128 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36130 inputType: 'hidden',
36133 labelSeparator: '',
36135 itemCls : 'x-form-item-display-none'
36143 * Ext JS Library 1.1.1
36144 * Copyright(c) 2006-2007, Ext JS, LLC.
36146 * Originally Released Under LGPL - original licence link has changed is not relivant.
36149 * <script type="text/javascript">
36153 * @class Roo.form.TriggerField
36154 * @extends Roo.form.TextField
36155 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36156 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36157 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36158 * for which you can provide a custom implementation. For example:
36160 var trigger = new Roo.form.TriggerField();
36161 trigger.onTriggerClick = myTriggerFn;
36162 trigger.applyTo('my-field');
36165 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36166 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36167 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36168 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36170 * Create a new TriggerField.
36171 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36172 * to the base TextField)
36174 Roo.form.TriggerField = function(config){
36175 this.mimicing = false;
36176 Roo.form.TriggerField.superclass.constructor.call(this, config);
36179 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36181 * @cfg {String} triggerClass A CSS class to apply to the trigger
36184 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36185 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36187 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36189 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36193 /** @cfg {Boolean} grow @hide */
36194 /** @cfg {Number} growMin @hide */
36195 /** @cfg {Number} growMax @hide */
36201 autoSize: Roo.emptyFn,
36205 deferHeight : true,
36208 actionMode : 'wrap',
36210 onResize : function(w, h){
36211 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36212 if(typeof w == 'number'){
36213 var x = w - this.trigger.getWidth();
36214 this.el.setWidth(this.adjustWidth('input', x));
36215 this.trigger.setStyle('left', x+'px');
36220 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36223 getResizeEl : function(){
36228 getPositionEl : function(){
36233 alignErrorIcon : function(){
36234 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36238 onRender : function(ct, position){
36239 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36240 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36241 this.trigger = this.wrap.createChild(this.triggerConfig ||
36242 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36243 if(this.hideTrigger){
36244 this.trigger.setDisplayed(false);
36246 this.initTrigger();
36248 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36253 initTrigger : function(){
36254 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36255 this.trigger.addClassOnOver('x-form-trigger-over');
36256 this.trigger.addClassOnClick('x-form-trigger-click');
36260 onDestroy : function(){
36262 this.trigger.removeAllListeners();
36263 this.trigger.remove();
36266 this.wrap.remove();
36268 Roo.form.TriggerField.superclass.onDestroy.call(this);
36272 onFocus : function(){
36273 Roo.form.TriggerField.superclass.onFocus.call(this);
36274 if(!this.mimicing){
36275 this.wrap.addClass('x-trigger-wrap-focus');
36276 this.mimicing = true;
36277 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36278 if(this.monitorTab){
36279 this.el.on("keydown", this.checkTab, this);
36285 checkTab : function(e){
36286 if(e.getKey() == e.TAB){
36287 this.triggerBlur();
36292 onBlur : function(){
36297 mimicBlur : function(e, t){
36298 if(!this.wrap.contains(t) && this.validateBlur()){
36299 this.triggerBlur();
36304 triggerBlur : function(){
36305 this.mimicing = false;
36306 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36307 if(this.monitorTab){
36308 this.el.un("keydown", this.checkTab, this);
36310 this.wrap.removeClass('x-trigger-wrap-focus');
36311 Roo.form.TriggerField.superclass.onBlur.call(this);
36315 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36316 validateBlur : function(e, t){
36321 onDisable : function(){
36322 Roo.form.TriggerField.superclass.onDisable.call(this);
36324 this.wrap.addClass('x-item-disabled');
36329 onEnable : function(){
36330 Roo.form.TriggerField.superclass.onEnable.call(this);
36332 this.wrap.removeClass('x-item-disabled');
36337 onShow : function(){
36338 var ae = this.getActionEl();
36341 ae.dom.style.display = '';
36342 ae.dom.style.visibility = 'visible';
36348 onHide : function(){
36349 var ae = this.getActionEl();
36350 ae.dom.style.display = 'none';
36354 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36355 * by an implementing function.
36357 * @param {EventObject} e
36359 onTriggerClick : Roo.emptyFn
36362 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36363 // to be extended by an implementing class. For an example of implementing this class, see the custom
36364 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36365 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36366 initComponent : function(){
36367 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36369 this.triggerConfig = {
36370 tag:'span', cls:'x-form-twin-triggers', cn:[
36371 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36372 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36376 getTrigger : function(index){
36377 return this.triggers[index];
36380 initTrigger : function(){
36381 var ts = this.trigger.select('.x-form-trigger', true);
36382 this.wrap.setStyle('overflow', 'hidden');
36383 var triggerField = this;
36384 ts.each(function(t, all, index){
36385 t.hide = function(){
36386 var w = triggerField.wrap.getWidth();
36387 this.dom.style.display = 'none';
36388 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36390 t.show = function(){
36391 var w = triggerField.wrap.getWidth();
36392 this.dom.style.display = '';
36393 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36395 var triggerIndex = 'Trigger'+(index+1);
36397 if(this['hide'+triggerIndex]){
36398 t.dom.style.display = 'none';
36400 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36401 t.addClassOnOver('x-form-trigger-over');
36402 t.addClassOnClick('x-form-trigger-click');
36404 this.triggers = ts.elements;
36407 onTrigger1Click : Roo.emptyFn,
36408 onTrigger2Click : Roo.emptyFn
36411 * Ext JS Library 1.1.1
36412 * Copyright(c) 2006-2007, Ext JS, LLC.
36414 * Originally Released Under LGPL - original licence link has changed is not relivant.
36417 * <script type="text/javascript">
36421 * @class Roo.form.TextArea
36422 * @extends Roo.form.TextField
36423 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36424 * support for auto-sizing.
36426 * Creates a new TextArea
36427 * @param {Object} config Configuration options
36429 Roo.form.TextArea = function(config){
36430 Roo.form.TextArea.superclass.constructor.call(this, config);
36431 // these are provided exchanges for backwards compat
36432 // minHeight/maxHeight were replaced by growMin/growMax to be
36433 // compatible with TextField growing config values
36434 if(this.minHeight !== undefined){
36435 this.growMin = this.minHeight;
36437 if(this.maxHeight !== undefined){
36438 this.growMax = this.maxHeight;
36442 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36444 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36448 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36452 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36453 * in the field (equivalent to setting overflow: hidden, defaults to false)
36455 preventScrollbars: false,
36457 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36458 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36462 onRender : function(ct, position){
36464 this.defaultAutoCreate = {
36466 style:"width:300px;height:60px;",
36467 autocomplete: "off"
36470 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36472 this.textSizeEl = Roo.DomHelper.append(document.body, {
36473 tag: "pre", cls: "x-form-grow-sizer"
36475 if(this.preventScrollbars){
36476 this.el.setStyle("overflow", "hidden");
36478 this.el.setHeight(this.growMin);
36482 onDestroy : function(){
36483 if(this.textSizeEl){
36484 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36486 Roo.form.TextArea.superclass.onDestroy.call(this);
36490 onKeyUp : function(e){
36491 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36497 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36498 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36500 autoSize : function(){
36501 if(!this.grow || !this.textSizeEl){
36505 var v = el.dom.value;
36506 var ts = this.textSizeEl;
36509 ts.appendChild(document.createTextNode(v));
36512 Roo.fly(ts).setWidth(this.el.getWidth());
36514 v = "  ";
36517 v = v.replace(/\n/g, '<p> </p>');
36519 v += " \n ";
36522 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36523 if(h != this.lastHeight){
36524 this.lastHeight = h;
36525 this.el.setHeight(h);
36526 this.fireEvent("autosize", this, h);
36531 * Ext JS Library 1.1.1
36532 * Copyright(c) 2006-2007, Ext JS, LLC.
36534 * Originally Released Under LGPL - original licence link has changed is not relivant.
36537 * <script type="text/javascript">
36542 * @class Roo.form.NumberField
36543 * @extends Roo.form.TextField
36544 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36546 * Creates a new NumberField
36547 * @param {Object} config Configuration options
36549 Roo.form.NumberField = function(config){
36550 Roo.form.NumberField.superclass.constructor.call(this, config);
36553 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36555 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36557 fieldClass: "x-form-field x-form-num-field",
36559 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36561 allowDecimals : true,
36563 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36565 decimalSeparator : ".",
36567 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36569 decimalPrecision : 2,
36571 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36573 allowNegative : true,
36575 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36577 minValue : Number.NEGATIVE_INFINITY,
36579 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36581 maxValue : Number.MAX_VALUE,
36583 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36585 minText : "The minimum value for this field is {0}",
36587 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36589 maxText : "The maximum value for this field is {0}",
36591 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36592 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36594 nanText : "{0} is not a valid number",
36597 initEvents : function(){
36598 Roo.form.NumberField.superclass.initEvents.call(this);
36599 var allowed = "0123456789";
36600 if(this.allowDecimals){
36601 allowed += this.decimalSeparator;
36603 if(this.allowNegative){
36606 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36607 var keyPress = function(e){
36608 var k = e.getKey();
36609 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36612 var c = e.getCharCode();
36613 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36617 this.el.on("keypress", keyPress, this);
36621 validateValue : function(value){
36622 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36625 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36628 var num = this.parseValue(value);
36630 this.markInvalid(String.format(this.nanText, value));
36633 if(num < this.minValue){
36634 this.markInvalid(String.format(this.minText, this.minValue));
36637 if(num > this.maxValue){
36638 this.markInvalid(String.format(this.maxText, this.maxValue));
36644 getValue : function(){
36645 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36649 parseValue : function(value){
36650 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36651 return isNaN(value) ? '' : value;
36655 fixPrecision : function(value){
36656 var nan = isNaN(value);
36657 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36658 return nan ? '' : value;
36660 return parseFloat(value).toFixed(this.decimalPrecision);
36663 setValue : function(v){
36664 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36668 decimalPrecisionFcn : function(v){
36669 return Math.floor(v);
36672 beforeBlur : function(){
36673 var v = this.parseValue(this.getRawValue());
36675 this.setValue(this.fixPrecision(v));
36680 * Ext JS Library 1.1.1
36681 * Copyright(c) 2006-2007, Ext JS, LLC.
36683 * Originally Released Under LGPL - original licence link has changed is not relivant.
36686 * <script type="text/javascript">
36690 * @class Roo.form.DateField
36691 * @extends Roo.form.TriggerField
36692 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36694 * Create a new DateField
36695 * @param {Object} config
36697 Roo.form.DateField = function(config){
36698 Roo.form.DateField.superclass.constructor.call(this, config);
36704 * Fires when a date is selected
36705 * @param {Roo.form.DateField} combo This combo box
36706 * @param {Date} date The date selected
36713 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36714 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36715 this.ddMatch = null;
36716 if(this.disabledDates){
36717 var dd = this.disabledDates;
36719 for(var i = 0; i < dd.length; i++){
36721 if(i != dd.length-1) re += "|";
36723 this.ddMatch = new RegExp(re + ")");
36727 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36729 * @cfg {String} format
36730 * The default date format string which can be overriden for localization support. The format must be
36731 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36735 * @cfg {String} altFormats
36736 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36737 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36739 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36741 * @cfg {Array} disabledDays
36742 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36744 disabledDays : null,
36746 * @cfg {String} disabledDaysText
36747 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36749 disabledDaysText : "Disabled",
36751 * @cfg {Array} disabledDates
36752 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36753 * expression so they are very powerful. Some examples:
36755 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36756 * <li>["03/08", "09/16"] would disable those days for every year</li>
36757 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36758 * <li>["03/../2006"] would disable every day in March 2006</li>
36759 * <li>["^03"] would disable every day in every March</li>
36761 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36762 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36764 disabledDates : null,
36766 * @cfg {String} disabledDatesText
36767 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36769 disabledDatesText : "Disabled",
36771 * @cfg {Date/String} minValue
36772 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36773 * valid format (defaults to null).
36777 * @cfg {Date/String} maxValue
36778 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36779 * valid format (defaults to null).
36783 * @cfg {String} minText
36784 * The error text to display when the date in the cell is before minValue (defaults to
36785 * 'The date in this field must be after {minValue}').
36787 minText : "The date in this field must be equal to or after {0}",
36789 * @cfg {String} maxText
36790 * The error text to display when the date in the cell is after maxValue (defaults to
36791 * 'The date in this field must be before {maxValue}').
36793 maxText : "The date in this field must be equal to or before {0}",
36795 * @cfg {String} invalidText
36796 * The error text to display when the date in the field is invalid (defaults to
36797 * '{value} is not a valid date - it must be in the format {format}').
36799 invalidText : "{0} is not a valid date - it must be in the format {1}",
36801 * @cfg {String} triggerClass
36802 * An additional CSS class used to style the trigger button. The trigger will always get the
36803 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36804 * which displays a calendar icon).
36806 triggerClass : 'x-form-date-trigger',
36810 * @cfg {bool} useIso
36811 * if enabled, then the date field will use a hidden field to store the
36812 * real value as iso formated date. default (false)
36816 * @cfg {String/Object} autoCreate
36817 * A DomHelper element spec, or true for a default element spec (defaults to
36818 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36821 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36824 hiddenField: false,
36826 onRender : function(ct, position)
36828 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36830 this.el.dom.removeAttribute('name');
36831 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36833 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36834 // prevent input submission
36835 this.hiddenName = this.name;
36842 validateValue : function(value)
36844 value = this.formatDate(value);
36845 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36848 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36851 var svalue = value;
36852 value = this.parseDate(value);
36854 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36857 var time = value.getTime();
36858 if(this.minValue && time < this.minValue.getTime()){
36859 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36862 if(this.maxValue && time > this.maxValue.getTime()){
36863 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36866 if(this.disabledDays){
36867 var day = value.getDay();
36868 for(var i = 0; i < this.disabledDays.length; i++) {
36869 if(day === this.disabledDays[i]){
36870 this.markInvalid(this.disabledDaysText);
36875 var fvalue = this.formatDate(value);
36876 if(this.ddMatch && this.ddMatch.test(fvalue)){
36877 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36884 // Provides logic to override the default TriggerField.validateBlur which just returns true
36885 validateBlur : function(){
36886 return !this.menu || !this.menu.isVisible();
36890 * Returns the current date value of the date field.
36891 * @return {Date} The date value
36893 getValue : function(){
36895 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36899 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36900 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36901 * (the default format used is "m/d/y").
36904 //All of these calls set the same date value (May 4, 2006)
36906 //Pass a date object:
36907 var dt = new Date('5/4/06');
36908 dateField.setValue(dt);
36910 //Pass a date string (default format):
36911 dateField.setValue('5/4/06');
36913 //Pass a date string (custom format):
36914 dateField.format = 'Y-m-d';
36915 dateField.setValue('2006-5-4');
36917 * @param {String/Date} date The date or valid date string
36919 setValue : function(date){
36920 if (this.hiddenField) {
36921 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36923 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36927 parseDate : function(value){
36928 if(!value || value instanceof Date){
36931 var v = Date.parseDate(value, this.format);
36932 if(!v && this.altFormats){
36933 if(!this.altFormatsArray){
36934 this.altFormatsArray = this.altFormats.split("|");
36936 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36937 v = Date.parseDate(value, this.altFormatsArray[i]);
36944 formatDate : function(date, fmt){
36945 return (!date || !(date instanceof Date)) ?
36946 date : date.dateFormat(fmt || this.format);
36951 select: function(m, d){
36953 this.fireEvent('select', this, d);
36955 show : function(){ // retain focus styling
36959 this.focus.defer(10, this);
36960 var ml = this.menuListeners;
36961 this.menu.un("select", ml.select, this);
36962 this.menu.un("show", ml.show, this);
36963 this.menu.un("hide", ml.hide, this);
36968 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36969 onTriggerClick : function(){
36973 if(this.menu == null){
36974 this.menu = new Roo.menu.DateMenu();
36976 Roo.apply(this.menu.picker, {
36977 showClear: this.allowBlank,
36978 minDate : this.minValue,
36979 maxDate : this.maxValue,
36980 disabledDatesRE : this.ddMatch,
36981 disabledDatesText : this.disabledDatesText,
36982 disabledDays : this.disabledDays,
36983 disabledDaysText : this.disabledDaysText,
36984 format : this.format,
36985 minText : String.format(this.minText, this.formatDate(this.minValue)),
36986 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36988 this.menu.on(Roo.apply({}, this.menuListeners, {
36991 this.menu.picker.setValue(this.getValue() || new Date());
36992 this.menu.show(this.el, "tl-bl?");
36995 beforeBlur : function(){
36996 var v = this.parseDate(this.getRawValue());
37002 /** @cfg {Boolean} grow @hide */
37003 /** @cfg {Number} growMin @hide */
37004 /** @cfg {Number} growMax @hide */
37011 * Ext JS Library 1.1.1
37012 * Copyright(c) 2006-2007, Ext JS, LLC.
37014 * Originally Released Under LGPL - original licence link has changed is not relivant.
37017 * <script type="text/javascript">
37022 * @class Roo.form.ComboBox
37023 * @extends Roo.form.TriggerField
37024 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37026 * Create a new ComboBox.
37027 * @param {Object} config Configuration options
37029 Roo.form.ComboBox = function(config){
37030 Roo.form.ComboBox.superclass.constructor.call(this, config);
37034 * Fires when the dropdown list is expanded
37035 * @param {Roo.form.ComboBox} combo This combo box
37040 * Fires when the dropdown list is collapsed
37041 * @param {Roo.form.ComboBox} combo This combo box
37045 * @event beforeselect
37046 * Fires before a list item is selected. Return false to cancel the selection.
37047 * @param {Roo.form.ComboBox} combo This combo box
37048 * @param {Roo.data.Record} record The data record returned from the underlying store
37049 * @param {Number} index The index of the selected item in the dropdown list
37051 'beforeselect' : true,
37054 * Fires when a list item is selected
37055 * @param {Roo.form.ComboBox} combo This combo box
37056 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37057 * @param {Number} index The index of the selected item in the dropdown list
37061 * @event beforequery
37062 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37063 * The event object passed has these properties:
37064 * @param {Roo.form.ComboBox} combo This combo box
37065 * @param {String} query The query
37066 * @param {Boolean} forceAll true to force "all" query
37067 * @param {Boolean} cancel true to cancel the query
37068 * @param {Object} e The query event object
37070 'beforequery': true,
37073 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37074 * @param {Roo.form.ComboBox} combo This combo box
37079 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37080 * @param {Roo.form.ComboBox} combo This combo box
37081 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37087 if(this.transform){
37088 this.allowDomMove = false;
37089 var s = Roo.getDom(this.transform);
37090 if(!this.hiddenName){
37091 this.hiddenName = s.name;
37094 this.mode = 'local';
37095 var d = [], opts = s.options;
37096 for(var i = 0, len = opts.length;i < len; i++){
37098 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37100 this.value = value;
37102 d.push([value, o.text]);
37104 this.store = new Roo.data.SimpleStore({
37106 fields: ['value', 'text'],
37109 this.valueField = 'value';
37110 this.displayField = 'text';
37112 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37113 if(!this.lazyRender){
37114 this.target = true;
37115 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37116 s.parentNode.removeChild(s); // remove it
37117 this.render(this.el.parentNode);
37119 s.parentNode.removeChild(s); // remove it
37124 this.store = Roo.factory(this.store, Roo.data);
37127 this.selectedIndex = -1;
37128 if(this.mode == 'local'){
37129 if(config.queryDelay === undefined){
37130 this.queryDelay = 10;
37132 if(config.minChars === undefined){
37138 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37140 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37143 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37144 * rendering into an Roo.Editor, defaults to false)
37147 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37148 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37151 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37154 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37155 * the dropdown list (defaults to undefined, with no header element)
37159 * @cfg {String/Roo.Template} tpl The template to use to render the output
37163 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37165 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37167 listWidth: undefined,
37169 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37170 * mode = 'remote' or 'text' if mode = 'local')
37172 displayField: undefined,
37174 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37175 * mode = 'remote' or 'value' if mode = 'local').
37176 * Note: use of a valueField requires the user make a selection
37177 * in order for a value to be mapped.
37179 valueField: undefined,
37181 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37182 * field's data value (defaults to the underlying DOM element's name)
37184 hiddenName: undefined,
37186 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37190 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37192 selectedClass: 'x-combo-selected',
37194 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37195 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37196 * which displays a downward arrow icon).
37198 triggerClass : 'x-form-arrow-trigger',
37200 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37204 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37205 * anchor positions (defaults to 'tl-bl')
37207 listAlign: 'tl-bl?',
37209 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37213 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37214 * query specified by the allQuery config option (defaults to 'query')
37216 triggerAction: 'query',
37218 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37219 * (defaults to 4, does not apply if editable = false)
37223 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37224 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37228 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37229 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37233 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37234 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37238 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37239 * when editable = true (defaults to false)
37241 selectOnFocus:false,
37243 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37245 queryParam: 'query',
37247 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37248 * when mode = 'remote' (defaults to 'Loading...')
37250 loadingText: 'Loading...',
37252 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37256 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37260 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37261 * traditional select (defaults to true)
37265 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37269 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37273 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37274 * listWidth has a higher value)
37278 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37279 * allow the user to set arbitrary text into the field (defaults to false)
37281 forceSelection:false,
37283 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37284 * if typeAhead = true (defaults to 250)
37286 typeAheadDelay : 250,
37288 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37289 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37291 valueNotFoundText : undefined,
37293 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37295 blockFocus : false,
37298 * @cfg {Boolean} disableClear Disable showing of clear button.
37300 disableClear : false,
37302 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37304 alwaysQuery : false,
37312 onRender : function(ct, position){
37313 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37314 if(this.hiddenName){
37315 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37317 this.hiddenField.value =
37318 this.hiddenValue !== undefined ? this.hiddenValue :
37319 this.value !== undefined ? this.value : '';
37321 // prevent input submission
37322 this.el.dom.removeAttribute('name');
37325 this.el.dom.setAttribute('autocomplete', 'off');
37328 var cls = 'x-combo-list';
37330 this.list = new Roo.Layer({
37331 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37334 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37335 this.list.setWidth(lw);
37336 this.list.swallowEvent('mousewheel');
37337 this.assetHeight = 0;
37340 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37341 this.assetHeight += this.header.getHeight();
37344 this.innerList = this.list.createChild({cls:cls+'-inner'});
37345 this.innerList.on('mouseover', this.onViewOver, this);
37346 this.innerList.on('mousemove', this.onViewMove, this);
37347 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37349 if(this.allowBlank && !this.pageSize && !this.disableClear){
37350 this.footer = this.list.createChild({cls:cls+'-ft'});
37351 this.pageTb = new Roo.Toolbar(this.footer);
37355 this.footer = this.list.createChild({cls:cls+'-ft'});
37356 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37357 {pageSize: this.pageSize});
37361 if (this.pageTb && this.allowBlank && !this.disableClear) {
37363 this.pageTb.add(new Roo.Toolbar.Fill(), {
37364 cls: 'x-btn-icon x-btn-clear',
37366 handler: function()
37369 _this.clearValue();
37370 _this.onSelect(false, -1);
37375 this.assetHeight += this.footer.getHeight();
37380 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37383 this.view = new Roo.View(this.innerList, this.tpl, {
37384 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37387 this.view.on('click', this.onViewClick, this);
37389 this.store.on('beforeload', this.onBeforeLoad, this);
37390 this.store.on('load', this.onLoad, this);
37391 this.store.on('loadexception', this.collapse, this);
37393 if(this.resizable){
37394 this.resizer = new Roo.Resizable(this.list, {
37395 pinned:true, handles:'se'
37397 this.resizer.on('resize', function(r, w, h){
37398 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37399 this.listWidth = w;
37400 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37401 this.restrictHeight();
37403 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37405 if(!this.editable){
37406 this.editable = true;
37407 this.setEditable(false);
37411 if (typeof(this.events.add.listeners) != 'undefined') {
37413 this.addicon = this.wrap.createChild(
37414 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37416 this.addicon.on('click', function(e) {
37417 this.fireEvent('add', this);
37420 if (typeof(this.events.edit.listeners) != 'undefined') {
37422 this.editicon = this.wrap.createChild(
37423 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37424 if (this.addicon) {
37425 this.editicon.setStyle('margin-left', '40px');
37427 this.editicon.on('click', function(e) {
37429 // we fire even if inothing is selected..
37430 this.fireEvent('edit', this, this.lastData );
37440 initEvents : function(){
37441 Roo.form.ComboBox.superclass.initEvents.call(this);
37443 this.keyNav = new Roo.KeyNav(this.el, {
37444 "up" : function(e){
37445 this.inKeyMode = true;
37449 "down" : function(e){
37450 if(!this.isExpanded()){
37451 this.onTriggerClick();
37453 this.inKeyMode = true;
37458 "enter" : function(e){
37459 this.onViewClick();
37463 "esc" : function(e){
37467 "tab" : function(e){
37468 this.onViewClick(false);
37474 doRelay : function(foo, bar, hname){
37475 if(hname == 'down' || this.scope.isExpanded()){
37476 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37483 this.queryDelay = Math.max(this.queryDelay || 10,
37484 this.mode == 'local' ? 10 : 250);
37485 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37486 if(this.typeAhead){
37487 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37489 if(this.editable !== false){
37490 this.el.on("keyup", this.onKeyUp, this);
37492 if(this.forceSelection){
37493 this.on('blur', this.doForce, this);
37497 onDestroy : function(){
37499 this.view.setStore(null);
37500 this.view.el.removeAllListeners();
37501 this.view.el.remove();
37502 this.view.purgeListeners();
37505 this.list.destroy();
37508 this.store.un('beforeload', this.onBeforeLoad, this);
37509 this.store.un('load', this.onLoad, this);
37510 this.store.un('loadexception', this.collapse, this);
37512 Roo.form.ComboBox.superclass.onDestroy.call(this);
37516 fireKey : function(e){
37517 if(e.isNavKeyPress() && !this.list.isVisible()){
37518 this.fireEvent("specialkey", this, e);
37523 onResize: function(w, h){
37524 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37526 if(typeof w != 'number'){
37527 // we do not handle it!?!?
37530 var tw = this.trigger.getWidth();
37531 tw += this.addicon ? this.addicon.getWidth() : 0;
37532 tw += this.editicon ? this.editicon.getWidth() : 0;
37534 this.el.setWidth( this.adjustWidth('input', x));
37536 this.trigger.setStyle('left', x+'px');
37538 if(this.list && this.listWidth === undefined){
37539 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37540 this.list.setWidth(lw);
37541 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37549 * Allow or prevent the user from directly editing the field text. If false is passed,
37550 * the user will only be able to select from the items defined in the dropdown list. This method
37551 * is the runtime equivalent of setting the 'editable' config option at config time.
37552 * @param {Boolean} value True to allow the user to directly edit the field text
37554 setEditable : function(value){
37555 if(value == this.editable){
37558 this.editable = value;
37560 this.el.dom.setAttribute('readOnly', true);
37561 this.el.on('mousedown', this.onTriggerClick, this);
37562 this.el.addClass('x-combo-noedit');
37564 this.el.dom.setAttribute('readOnly', false);
37565 this.el.un('mousedown', this.onTriggerClick, this);
37566 this.el.removeClass('x-combo-noedit');
37571 onBeforeLoad : function(){
37572 if(!this.hasFocus){
37575 this.innerList.update(this.loadingText ?
37576 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37577 this.restrictHeight();
37578 this.selectedIndex = -1;
37582 onLoad : function(){
37583 if(!this.hasFocus){
37586 if(this.store.getCount() > 0){
37588 this.restrictHeight();
37589 if(this.lastQuery == this.allQuery){
37591 this.el.dom.select();
37593 if(!this.selectByValue(this.value, true)){
37594 this.select(0, true);
37598 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37599 this.taTask.delay(this.typeAheadDelay);
37603 this.onEmptyResults();
37609 onTypeAhead : function(){
37610 if(this.store.getCount() > 0){
37611 var r = this.store.getAt(0);
37612 var newValue = r.data[this.displayField];
37613 var len = newValue.length;
37614 var selStart = this.getRawValue().length;
37615 if(selStart != len){
37616 this.setRawValue(newValue);
37617 this.selectText(selStart, newValue.length);
37623 onSelect : function(record, index){
37624 if(this.fireEvent('beforeselect', this, record, index) !== false){
37625 this.setFromData(index > -1 ? record.data : false);
37627 this.fireEvent('select', this, record, index);
37632 * Returns the currently selected field value or empty string if no value is set.
37633 * @return {String} value The selected value
37635 getValue : function(){
37636 if(this.valueField){
37637 return typeof this.value != 'undefined' ? this.value : '';
37639 return Roo.form.ComboBox.superclass.getValue.call(this);
37644 * Clears any text/value currently set in the field
37646 clearValue : function(){
37647 if(this.hiddenField){
37648 this.hiddenField.value = '';
37651 this.setRawValue('');
37652 this.lastSelectionText = '';
37653 this.applyEmptyText();
37657 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37658 * will be displayed in the field. If the value does not match the data value of an existing item,
37659 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37660 * Otherwise the field will be blank (although the value will still be set).
37661 * @param {String} value The value to match
37663 setValue : function(v){
37665 if(this.valueField){
37666 var r = this.findRecord(this.valueField, v);
37668 text = r.data[this.displayField];
37669 }else if(this.valueNotFoundText !== undefined){
37670 text = this.valueNotFoundText;
37673 this.lastSelectionText = text;
37674 if(this.hiddenField){
37675 this.hiddenField.value = v;
37677 Roo.form.ComboBox.superclass.setValue.call(this, text);
37681 * @property {Object} the last set data for the element
37686 * Sets the value of the field based on a object which is related to the record format for the store.
37687 * @param {Object} value the value to set as. or false on reset?
37689 setFromData : function(o){
37690 var dv = ''; // display value
37691 var vv = ''; // value value..
37693 if (this.displayField) {
37694 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37696 // this is an error condition!!!
37697 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37700 if(this.valueField){
37701 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37703 if(this.hiddenField){
37704 this.hiddenField.value = vv;
37706 this.lastSelectionText = dv;
37707 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37711 // no hidden field.. - we store the value in 'value', but still display
37712 // display field!!!!
37713 this.lastSelectionText = dv;
37714 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37720 reset : function(){
37721 // overridden so that last data is reset..
37722 this.setValue(this.originalValue);
37723 this.clearInvalid();
37724 this.lastData = false;
37727 findRecord : function(prop, value){
37729 if(this.store.getCount() > 0){
37730 this.store.each(function(r){
37731 if(r.data[prop] == value){
37741 onViewMove : function(e, t){
37742 this.inKeyMode = false;
37746 onViewOver : function(e, t){
37747 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37750 var item = this.view.findItemFromChild(t);
37752 var index = this.view.indexOf(item);
37753 this.select(index, false);
37758 onViewClick : function(doFocus){
37759 var index = this.view.getSelectedIndexes()[0];
37760 var r = this.store.getAt(index);
37762 this.onSelect(r, index);
37764 if(doFocus !== false && !this.blockFocus){
37770 restrictHeight : function(){
37771 this.innerList.dom.style.height = '';
37772 var inner = this.innerList.dom;
37773 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37774 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37775 this.list.beginUpdate();
37776 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37777 this.list.alignTo(this.el, this.listAlign);
37778 this.list.endUpdate();
37782 onEmptyResults : function(){
37787 * Returns true if the dropdown list is expanded, else false.
37789 isExpanded : function(){
37790 return this.list.isVisible();
37794 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37795 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37796 * @param {String} value The data value of the item to select
37797 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37798 * selected item if it is not currently in view (defaults to true)
37799 * @return {Boolean} True if the value matched an item in the list, else false
37801 selectByValue : function(v, scrollIntoView){
37802 if(v !== undefined && v !== null){
37803 var r = this.findRecord(this.valueField || this.displayField, v);
37805 this.select(this.store.indexOf(r), scrollIntoView);
37813 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37814 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37815 * @param {Number} index The zero-based index of the list item to select
37816 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37817 * selected item if it is not currently in view (defaults to true)
37819 select : function(index, scrollIntoView){
37820 this.selectedIndex = index;
37821 this.view.select(index);
37822 if(scrollIntoView !== false){
37823 var el = this.view.getNode(index);
37825 this.innerList.scrollChildIntoView(el, false);
37831 selectNext : function(){
37832 var ct = this.store.getCount();
37834 if(this.selectedIndex == -1){
37836 }else if(this.selectedIndex < ct-1){
37837 this.select(this.selectedIndex+1);
37843 selectPrev : function(){
37844 var ct = this.store.getCount();
37846 if(this.selectedIndex == -1){
37848 }else if(this.selectedIndex != 0){
37849 this.select(this.selectedIndex-1);
37855 onKeyUp : function(e){
37856 if(this.editable !== false && !e.isSpecialKey()){
37857 this.lastKey = e.getKey();
37858 this.dqTask.delay(this.queryDelay);
37863 validateBlur : function(){
37864 return !this.list || !this.list.isVisible();
37868 initQuery : function(){
37869 this.doQuery(this.getRawValue());
37873 doForce : function(){
37874 if(this.el.dom.value.length > 0){
37875 this.el.dom.value =
37876 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37877 this.applyEmptyText();
37882 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37883 * query allowing the query action to be canceled if needed.
37884 * @param {String} query The SQL query to execute
37885 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37886 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37887 * saved in the current store (defaults to false)
37889 doQuery : function(q, forceAll){
37890 if(q === undefined || q === null){
37895 forceAll: forceAll,
37899 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37903 forceAll = qe.forceAll;
37904 if(forceAll === true || (q.length >= this.minChars)){
37905 if(this.lastQuery != q || this.alwaysQuery){
37906 this.lastQuery = q;
37907 if(this.mode == 'local'){
37908 this.selectedIndex = -1;
37910 this.store.clearFilter();
37912 this.store.filter(this.displayField, q);
37916 this.store.baseParams[this.queryParam] = q;
37918 params: this.getParams(q)
37923 this.selectedIndex = -1;
37930 getParams : function(q){
37932 //p[this.queryParam] = q;
37935 p.limit = this.pageSize;
37941 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37943 collapse : function(){
37944 if(!this.isExpanded()){
37948 Roo.get(document).un('mousedown', this.collapseIf, this);
37949 Roo.get(document).un('mousewheel', this.collapseIf, this);
37950 if (!this.editable) {
37951 Roo.get(document).un('keydown', this.listKeyPress, this);
37953 this.fireEvent('collapse', this);
37957 collapseIf : function(e){
37958 if(!e.within(this.wrap) && !e.within(this.list)){
37964 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37966 expand : function(){
37967 if(this.isExpanded() || !this.hasFocus){
37970 this.list.alignTo(this.el, this.listAlign);
37972 Roo.get(document).on('mousedown', this.collapseIf, this);
37973 Roo.get(document).on('mousewheel', this.collapseIf, this);
37974 if (!this.editable) {
37975 Roo.get(document).on('keydown', this.listKeyPress, this);
37978 this.fireEvent('expand', this);
37982 // Implements the default empty TriggerField.onTriggerClick function
37983 onTriggerClick : function(){
37987 if(this.isExpanded()){
37989 if (!this.blockFocus) {
37994 this.hasFocus = true;
37995 if(this.triggerAction == 'all') {
37996 this.doQuery(this.allQuery, true);
37998 this.doQuery(this.getRawValue());
38000 if (!this.blockFocus) {
38005 listKeyPress : function(e)
38007 //Roo.log('listkeypress');
38008 // scroll to first matching element based on key pres..
38009 if (e.isSpecialKey()) {
38012 var k = String.fromCharCode(e.getKey()).toUpperCase();
38015 var csel = this.view.getSelectedNodes();
38016 var cselitem = false;
38018 var ix = this.view.indexOf(csel[0]);
38019 cselitem = this.store.getAt(ix);
38020 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38026 this.store.each(function(v) {
38028 // start at existing selection.
38029 if (cselitem.id == v.id) {
38035 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38036 match = this.store.indexOf(v);
38041 if (match === false) {
38042 return true; // no more action?
38045 this.view.select(match);
38046 var sn = Roo.get(this.view.getSelectedNodes()[0])
38047 sn.scrollIntoView(sn.dom.parentNode, false);
38051 * @cfg {Boolean} grow
38055 * @cfg {Number} growMin
38059 * @cfg {Number} growMax
38068 * Ext JS Library 1.1.1
38069 * Copyright(c) 2006-2007, Ext JS, LLC.
38071 * Originally Released Under LGPL - original licence link has changed is not relivant.
38074 * <script type="text/javascript">
38077 * @class Roo.form.Checkbox
38078 * @extends Roo.form.Field
38079 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38081 * Creates a new Checkbox
38082 * @param {Object} config Configuration options
38084 Roo.form.Checkbox = function(config){
38085 Roo.form.Checkbox.superclass.constructor.call(this, config);
38089 * Fires when the checkbox is checked or unchecked.
38090 * @param {Roo.form.Checkbox} this This checkbox
38091 * @param {Boolean} checked The new checked value
38097 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38099 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38101 focusClass : undefined,
38103 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38105 fieldClass: "x-form-field",
38107 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38111 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38112 * {tag: "input", type: "checkbox", autocomplete: "off"})
38114 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38116 * @cfg {String} boxLabel The text that appears beside the checkbox
38120 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38124 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38126 valueOff: '0', // value when not checked..
38128 actionMode : 'viewEl',
38131 itemCls : 'x-menu-check-item x-form-item',
38132 groupClass : 'x-menu-group-item',
38133 inputType : 'hidden',
38136 inSetChecked: false, // check that we are not calling self...
38138 inputElement: false, // real input element?
38139 basedOn: false, // ????
38141 isFormField: true, // not sure where this is needed!!!!
38143 onResize : function(){
38144 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38145 if(!this.boxLabel){
38146 this.el.alignTo(this.wrap, 'c-c');
38150 initEvents : function(){
38151 Roo.form.Checkbox.superclass.initEvents.call(this);
38152 this.el.on("click", this.onClick, this);
38153 this.el.on("change", this.onClick, this);
38157 getResizeEl : function(){
38161 getPositionEl : function(){
38166 onRender : function(ct, position){
38167 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38169 if(this.inputValue !== undefined){
38170 this.el.dom.value = this.inputValue;
38173 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38174 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38175 var viewEl = this.wrap.createChild({
38176 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38177 this.viewEl = viewEl;
38178 this.wrap.on('click', this.onClick, this);
38180 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38181 this.el.on('propertychange', this.setFromHidden, this); //ie
38186 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38187 // viewEl.on('click', this.onClick, this);
38189 //if(this.checked){
38190 this.setChecked(this.checked);
38192 //this.checked = this.el.dom;
38198 initValue : Roo.emptyFn,
38201 * Returns the checked state of the checkbox.
38202 * @return {Boolean} True if checked, else false
38204 getValue : function(){
38206 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38208 return this.valueOff;
38213 onClick : function(){
38214 this.setChecked(!this.checked);
38216 //if(this.el.dom.checked != this.checked){
38217 // this.setValue(this.el.dom.checked);
38222 * Sets the checked state of the checkbox.
38223 * On is always based on a string comparison between inputValue and the param.
38224 * @param {Boolean/String} value - the value to set
38225 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38227 setValue : function(v,suppressEvent){
38230 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38231 //if(this.el && this.el.dom){
38232 // this.el.dom.checked = this.checked;
38233 // this.el.dom.defaultChecked = this.checked;
38235 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38236 //this.fireEvent("check", this, this.checked);
38239 setChecked : function(state,suppressEvent)
38241 if (this.inSetChecked) {
38242 this.checked = state;
38248 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38250 this.checked = state;
38251 if(suppressEvent !== true){
38252 this.fireEvent('check', this, state);
38254 this.inSetChecked = true;
38255 this.el.dom.value = state ? this.inputValue : this.valueOff;
38256 this.inSetChecked = false;
38259 // handle setting of hidden value by some other method!!?!?
38260 setFromHidden: function()
38265 //console.log("SET FROM HIDDEN");
38266 //alert('setFrom hidden');
38267 this.setValue(this.el.dom.value);
38270 onDestroy : function()
38273 Roo.get(this.viewEl).remove();
38276 Roo.form.Checkbox.superclass.onDestroy.call(this);
38281 * Ext JS Library 1.1.1
38282 * Copyright(c) 2006-2007, Ext JS, LLC.
38284 * Originally Released Under LGPL - original licence link has changed is not relivant.
38287 * <script type="text/javascript">
38291 * @class Roo.form.Radio
38292 * @extends Roo.form.Checkbox
38293 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38294 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38296 * Creates a new Radio
38297 * @param {Object} config Configuration options
38299 Roo.form.Radio = function(){
38300 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38302 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38303 inputType: 'radio',
38306 * If this radio is part of a group, it will return the selected value
38309 getGroupValue : function(){
38310 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38312 });//<script type="text/javascript">
38315 * Ext JS Library 1.1.1
38316 * Copyright(c) 2006-2007, Ext JS, LLC.
38317 * licensing@extjs.com
38319 * http://www.extjs.com/license
38325 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38326 * - IE ? - no idea how much works there.
38334 * @class Ext.form.HtmlEditor
38335 * @extends Ext.form.Field
38336 * Provides a lightweight HTML Editor component.
38337 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38339 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38340 * supported by this editor.</b><br/><br/>
38341 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38342 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38344 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38346 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38350 * @cfg {String} createLinkText The default text for the create link prompt
38352 createLinkText : 'Please enter the URL for the link:',
38354 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38356 defaultLinkValue : 'http:/'+'/',
38362 // private properties
38363 validationEvent : false,
38365 initialized : false,
38367 sourceEditMode : false,
38368 onFocus : Roo.emptyFn,
38370 hideMode:'offsets',
38371 defaultAutoCreate : {
38373 style:"width:500px;height:300px;",
38374 autocomplete: "off"
38378 initComponent : function(){
38381 * @event initialize
38382 * Fires when the editor is fully initialized (including the iframe)
38383 * @param {HtmlEditor} this
38388 * Fires when the editor is first receives the focus. Any insertion must wait
38389 * until after this event.
38390 * @param {HtmlEditor} this
38394 * @event beforesync
38395 * Fires before the textarea is updated with content from the editor iframe. Return false
38396 * to cancel the sync.
38397 * @param {HtmlEditor} this
38398 * @param {String} html
38402 * @event beforepush
38403 * Fires before the iframe editor is updated with content from the textarea. Return false
38404 * to cancel the push.
38405 * @param {HtmlEditor} this
38406 * @param {String} html
38411 * Fires when the textarea is updated with content from the editor iframe.
38412 * @param {HtmlEditor} this
38413 * @param {String} html
38418 * Fires when the iframe editor is updated with content from the textarea.
38419 * @param {HtmlEditor} this
38420 * @param {String} html
38424 * @event editmodechange
38425 * Fires when the editor switches edit modes
38426 * @param {HtmlEditor} this
38427 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38429 editmodechange: true,
38431 * @event editorevent
38432 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38433 * @param {HtmlEditor} this
38440 * Protected method that will not generally be called directly. It
38441 * is called when the editor creates its toolbar. Override this method if you need to
38442 * add custom toolbar buttons.
38443 * @param {HtmlEditor} editor
38445 createToolbar : function(editor){
38446 if (!editor.toolbars || !editor.toolbars.length) {
38447 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38450 for (var i =0 ; i < editor.toolbars.length;i++) {
38451 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38452 editor.toolbars[i].init(editor);
38459 * Protected method that will not generally be called directly. It
38460 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38461 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38463 getDocMarkup : function(){
38464 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38468 onRender : function(ct, position){
38469 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38470 this.el.dom.style.border = '0 none';
38471 this.el.dom.setAttribute('tabIndex', -1);
38472 this.el.addClass('x-hidden');
38473 if(Roo.isIE){ // fix IE 1px bogus margin
38474 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38476 this.wrap = this.el.wrap({
38477 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38480 this.frameId = Roo.id();
38481 this.createToolbar(this);
38488 var iframe = this.wrap.createChild({
38491 name: this.frameId,
38492 frameBorder : 'no',
38493 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38496 // console.log(iframe);
38497 //this.wrap.dom.appendChild(iframe);
38499 this.iframe = iframe.dom;
38501 this.assignDocWin();
38503 this.doc.designMode = 'on';
38506 this.doc.write(this.getDocMarkup());
38510 var task = { // must defer to wait for browser to be ready
38512 //console.log("run task?" + this.doc.readyState);
38513 this.assignDocWin();
38514 if(this.doc.body || this.doc.readyState == 'complete'){
38516 this.doc.designMode="on";
38520 Roo.TaskMgr.stop(task);
38521 this.initEditor.defer(10, this);
38528 Roo.TaskMgr.start(task);
38531 this.setSize(this.el.getSize());
38536 onResize : function(w, h){
38537 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38538 if(this.el && this.iframe){
38539 if(typeof w == 'number'){
38540 var aw = w - this.wrap.getFrameWidth('lr');
38541 this.el.setWidth(this.adjustWidth('textarea', aw));
38542 this.iframe.style.width = aw + 'px';
38544 if(typeof h == 'number'){
38546 for (var i =0; i < this.toolbars.length;i++) {
38547 // fixme - ask toolbars for heights?
38548 tbh += this.toolbars[i].tb.el.getHeight();
38554 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38555 this.el.setHeight(this.adjustWidth('textarea', ah));
38556 this.iframe.style.height = ah + 'px';
38558 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38565 * Toggles the editor between standard and source edit mode.
38566 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38568 toggleSourceEdit : function(sourceEditMode){
38570 this.sourceEditMode = sourceEditMode === true;
38572 if(this.sourceEditMode){
38575 this.iframe.className = 'x-hidden';
38576 this.el.removeClass('x-hidden');
38577 this.el.dom.removeAttribute('tabIndex');
38582 this.iframe.className = '';
38583 this.el.addClass('x-hidden');
38584 this.el.dom.setAttribute('tabIndex', -1);
38587 this.setSize(this.wrap.getSize());
38588 this.fireEvent('editmodechange', this, this.sourceEditMode);
38591 // private used internally
38592 createLink : function(){
38593 var url = prompt(this.createLinkText, this.defaultLinkValue);
38594 if(url && url != 'http:/'+'/'){
38595 this.relayCmd('createlink', url);
38599 // private (for BoxComponent)
38600 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38602 // private (for BoxComponent)
38603 getResizeEl : function(){
38607 // private (for BoxComponent)
38608 getPositionEl : function(){
38613 initEvents : function(){
38614 this.originalValue = this.getValue();
38618 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38621 markInvalid : Roo.emptyFn,
38623 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38626 clearInvalid : Roo.emptyFn,
38628 setValue : function(v){
38629 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38634 * Protected method that will not generally be called directly. If you need/want
38635 * custom HTML cleanup, this is the method you should override.
38636 * @param {String} html The HTML to be cleaned
38637 * return {String} The cleaned HTML
38639 cleanHtml : function(html){
38640 html = String(html);
38641 if(html.length > 5){
38642 if(Roo.isSafari){ // strip safari nonsense
38643 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38646 if(html == ' '){
38653 * Protected method that will not generally be called directly. Syncs the contents
38654 * of the editor iframe with the textarea.
38656 syncValue : function(){
38657 if(this.initialized){
38658 var bd = (this.doc.body || this.doc.documentElement);
38659 var html = bd.innerHTML;
38661 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38662 var m = bs.match(/text-align:(.*?);/i);
38664 html = '<div style="'+m[0]+'">' + html + '</div>';
38667 html = this.cleanHtml(html);
38668 if(this.fireEvent('beforesync', this, html) !== false){
38669 this.el.dom.value = html;
38670 this.fireEvent('sync', this, html);
38676 * Protected method that will not generally be called directly. Pushes the value of the textarea
38677 * into the iframe editor.
38679 pushValue : function(){
38680 if(this.initialized){
38681 var v = this.el.dom.value;
38685 if(this.fireEvent('beforepush', this, v) !== false){
38686 (this.doc.body || this.doc.documentElement).innerHTML = v;
38687 this.fireEvent('push', this, v);
38693 deferFocus : function(){
38694 this.focus.defer(10, this);
38698 focus : function(){
38699 if(this.win && !this.sourceEditMode){
38706 assignDocWin: function()
38708 var iframe = this.iframe;
38711 this.doc = iframe.contentWindow.document;
38712 this.win = iframe.contentWindow;
38714 if (!Roo.get(this.frameId)) {
38717 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38718 this.win = Roo.get(this.frameId).dom.contentWindow;
38723 initEditor : function(){
38724 //console.log("INIT EDITOR");
38725 this.assignDocWin();
38729 this.doc.designMode="on";
38731 this.doc.write(this.getDocMarkup());
38734 var dbody = (this.doc.body || this.doc.documentElement);
38735 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38736 // this copies styles from the containing element into thsi one..
38737 // not sure why we need all of this..
38738 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38739 ss['background-attachment'] = 'fixed'; // w3c
38740 dbody.bgProperties = 'fixed'; // ie
38741 Roo.DomHelper.applyStyles(dbody, ss);
38742 Roo.EventManager.on(this.doc, {
38743 'mousedown': this.onEditorEvent,
38744 'dblclick': this.onEditorEvent,
38745 'click': this.onEditorEvent,
38746 'keyup': this.onEditorEvent,
38751 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38753 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38754 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38756 this.initialized = true;
38758 this.fireEvent('initialize', this);
38763 onDestroy : function(){
38769 for (var i =0; i < this.toolbars.length;i++) {
38770 // fixme - ask toolbars for heights?
38771 this.toolbars[i].onDestroy();
38774 this.wrap.dom.innerHTML = '';
38775 this.wrap.remove();
38780 onFirstFocus : function(){
38782 this.assignDocWin();
38785 this.activated = true;
38786 for (var i =0; i < this.toolbars.length;i++) {
38787 this.toolbars[i].onFirstFocus();
38790 if(Roo.isGecko){ // prevent silly gecko errors
38792 var s = this.win.getSelection();
38793 if(!s.focusNode || s.focusNode.nodeType != 3){
38794 var r = s.getRangeAt(0);
38795 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38800 this.execCmd('useCSS', true);
38801 this.execCmd('styleWithCSS', false);
38804 this.fireEvent('activate', this);
38808 adjustFont: function(btn){
38809 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38810 //if(Roo.isSafari){ // safari
38813 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38814 if(Roo.isSafari){ // safari
38815 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38816 v = (v < 10) ? 10 : v;
38817 v = (v > 48) ? 48 : v;
38818 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38823 v = Math.max(1, v+adjust);
38825 this.execCmd('FontSize', v );
38828 onEditorEvent : function(e){
38829 this.fireEvent('editorevent', this, e);
38830 // this.updateToolbar();
38834 insertTag : function(tg)
38836 // could be a bit smarter... -> wrap the current selected tRoo..
38838 this.execCmd("formatblock", tg);
38842 insertText : function(txt)
38846 range = this.createRange();
38847 range.deleteContents();
38848 //alert(Sender.getAttribute('label'));
38850 range.insertNode(this.doc.createTextNode(txt));
38854 relayBtnCmd : function(btn){
38855 this.relayCmd(btn.cmd);
38859 * Executes a Midas editor command on the editor document and performs necessary focus and
38860 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38861 * @param {String} cmd The Midas command
38862 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38864 relayCmd : function(cmd, value){
38866 this.execCmd(cmd, value);
38867 this.fireEvent('editorevent', this);
38868 //this.updateToolbar();
38873 * Executes a Midas editor command directly on the editor document.
38874 * For visual commands, you should use {@link #relayCmd} instead.
38875 * <b>This should only be called after the editor is initialized.</b>
38876 * @param {String} cmd The Midas command
38877 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38879 execCmd : function(cmd, value){
38880 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38886 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38888 * @param {String} text
38890 insertAtCursor : function(text){
38891 if(!this.activated){
38896 var r = this.doc.selection.createRange();
38903 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38905 this.execCmd('InsertHTML', text);
38910 mozKeyPress : function(e){
38912 var c = e.getCharCode(), cmd;
38915 c = String.fromCharCode(c).toLowerCase();
38926 this.cleanUpPaste.defer(100, this);
38934 e.preventDefault();
38942 fixKeys : function(){ // load time branching for fastest keydown performance
38944 return function(e){
38945 var k = e.getKey(), r;
38948 r = this.doc.selection.createRange();
38951 r.pasteHTML('    ');
38958 r = this.doc.selection.createRange();
38960 var target = r.parentElement();
38961 if(!target || target.tagName.toLowerCase() != 'li'){
38963 r.pasteHTML('<br />');
38969 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38970 this.cleanUpPaste.defer(100, this);
38976 }else if(Roo.isOpera){
38977 return function(e){
38978 var k = e.getKey();
38982 this.execCmd('InsertHTML','    ');
38985 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38986 this.cleanUpPaste.defer(100, this);
38991 }else if(Roo.isSafari){
38992 return function(e){
38993 var k = e.getKey();
38997 this.execCmd('InsertText','\t');
39001 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39002 this.cleanUpPaste.defer(100, this);
39010 getAllAncestors: function()
39012 var p = this.getSelectedNode();
39015 a.push(p); // push blank onto stack..
39016 p = this.getParentElement();
39020 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39024 a.push(this.doc.body);
39028 lastSelNode : false,
39031 getSelection : function()
39033 this.assignDocWin();
39034 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39037 getSelectedNode: function()
39039 // this may only work on Gecko!!!
39041 // should we cache this!!!!
39046 var range = this.createRange(this.getSelection());
39049 var parent = range.parentElement();
39051 var testRange = range.duplicate();
39052 testRange.moveToElementText(parent);
39053 if (testRange.inRange(range)) {
39056 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39059 parent = parent.parentElement;
39065 var ar = range.endContainer.childNodes;
39067 ar = range.commonAncestorContainer.childNodes;
39068 //alert(ar.length);
39071 var other_nodes = [];
39072 var has_other_nodes = false;
39073 for (var i=0;i<ar.length;i++) {
39074 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39077 // fullly contained node.
39079 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39084 // probably selected..
39085 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39086 other_nodes.push(ar[i]);
39089 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39094 has_other_nodes = true;
39096 if (!nodes.length && other_nodes.length) {
39097 nodes= other_nodes;
39099 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39105 createRange: function(sel)
39107 // this has strange effects when using with
39108 // top toolbar - not sure if it's a great idea.
39109 //this.editor.contentWindow.focus();
39110 if (typeof sel != "undefined") {
39112 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39114 return this.doc.createRange();
39117 return this.doc.createRange();
39120 getParentElement: function()
39123 this.assignDocWin();
39124 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39126 var range = this.createRange(sel);
39129 var p = range.commonAncestorContainer;
39130 while (p.nodeType == 3) { // text node
39142 // BC Hacks - cause I cant work out what i was trying to do..
39143 rangeIntersectsNode : function(range, node)
39145 var nodeRange = node.ownerDocument.createRange();
39147 nodeRange.selectNode(node);
39150 nodeRange.selectNodeContents(node);
39153 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39154 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39156 rangeCompareNode : function(range, node) {
39157 var nodeRange = node.ownerDocument.createRange();
39159 nodeRange.selectNode(node);
39161 nodeRange.selectNodeContents(node);
39163 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39164 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39166 if (nodeIsBefore && !nodeIsAfter)
39168 if (!nodeIsBefore && nodeIsAfter)
39170 if (nodeIsBefore && nodeIsAfter)
39176 // private? - in a new class?
39177 cleanUpPaste : function()
39179 // cleans up the whole document..
39180 // console.log('cleanuppaste');
39181 this.cleanUpChildren(this.doc.body)
39185 cleanUpChildren : function (n)
39187 if (!n.childNodes.length) {
39190 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39191 this.cleanUpChild(n.childNodes[i]);
39198 cleanUpChild : function (node)
39200 //console.log(node);
39201 if (node.nodeName == "#text") {
39202 // clean up silly Windows -- stuff?
39205 if (node.nodeName == "#comment") {
39206 node.parentNode.removeChild(node);
39207 // clean up silly Windows -- stuff?
39211 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39213 node.parentNode.removeChild(node);
39217 if (!node.attributes || !node.attributes.length) {
39218 this.cleanUpChildren(node);
39222 function cleanAttr(n,v)
39225 if (v.match(/^\./) || v.match(/^\//)) {
39228 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39231 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39232 node.removeAttribute(n);
39236 function cleanStyle(n,v)
39238 if (v.match(/expression/)) { //XSS?? should we even bother..
39239 node.removeAttribute(n);
39244 var parts = v.split(/;/);
39245 Roo.each(parts, function(p) {
39246 p = p.replace(/\s+/g,'');
39250 var l = p.split(':').shift().replace(/\s+/g,'');
39252 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39253 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39254 node.removeAttribute(n);
39263 for (var i = node.attributes.length-1; i > -1 ; i--) {
39264 var a = node.attributes[i];
39266 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39267 node.removeAttribute(a.name);
39270 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39271 cleanAttr(a.name,a.value); // fixme..
39274 if (a.name == 'style') {
39275 cleanStyle(a.name,a.value);
39277 /// clean up MS crap..
39278 if (a.name == 'class') {
39279 if (a.value.match(/^Mso/)) {
39280 node.className = '';
39290 this.cleanUpChildren(node);
39296 // hide stuff that is not compatible
39310 * @event specialkey
39314 * @cfg {String} fieldClass @hide
39317 * @cfg {String} focusClass @hide
39320 * @cfg {String} autoCreate @hide
39323 * @cfg {String} inputType @hide
39326 * @cfg {String} invalidClass @hide
39329 * @cfg {String} invalidText @hide
39332 * @cfg {String} msgFx @hide
39335 * @cfg {String} validateOnBlur @hide
39339 Roo.form.HtmlEditor.white = [
39340 'area', 'br', 'img', 'input', 'hr', 'wbr',
39342 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39343 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39344 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39345 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39346 'table', 'ul', 'xmp',
39348 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39351 'dir', 'menu', 'ol', 'ul', 'dl',
39357 Roo.form.HtmlEditor.black = [
39358 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39360 'base', 'basefont', 'bgsound', 'blink', 'body',
39361 'frame', 'frameset', 'head', 'html', 'ilayer',
39362 'iframe', 'layer', 'link', 'meta', 'object',
39363 'script', 'style' ,'title', 'xml' // clean later..
39365 Roo.form.HtmlEditor.clean = [
39366 'script', 'style', 'title', 'xml'
39371 Roo.form.HtmlEditor.ablack = [
39375 Roo.form.HtmlEditor.aclean = [
39376 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39380 Roo.form.HtmlEditor.pwhite= [
39381 'http', 'https', 'mailto'
39384 Roo.form.HtmlEditor.cwhite= [
39389 // <script type="text/javascript">
39392 * Ext JS Library 1.1.1
39393 * Copyright(c) 2006-2007, Ext JS, LLC.
39399 * @class Roo.form.HtmlEditorToolbar1
39404 new Roo.form.HtmlEditor({
39407 new Roo.form.HtmlEditorToolbar1({
39408 disable : { fonts: 1 , format: 1, ..., ... , ...],
39414 * @cfg {Object} disable List of elements to disable..
39415 * @cfg {Array} btns List of additional buttons.
39419 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39422 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39425 Roo.apply(this, config);
39426 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39427 // dont call parent... till later.
39430 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39438 * @cfg {Object} disable List of toolbar elements to disable
39443 * @cfg {Array} fontFamilies An array of available font families
39461 // "á" , ?? a acute?
39466 "°" // , // degrees
39468 // "é" , // e ecute
39469 // "ú" , // u ecute?
39472 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39473 "input:submit", "input:button", "select", "textarea", "label" ],
39476 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39478 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39481 * @cfg {String} defaultFont default font to use.
39483 defaultFont: 'tahoma',
39485 fontSelect : false,
39488 formatCombo : false,
39490 init : function(editor)
39492 this.editor = editor;
39495 var fid = editor.frameId;
39497 function btn(id, toggle, handler){
39498 var xid = fid + '-'+ id ;
39502 cls : 'x-btn-icon x-edit-'+id,
39503 enableToggle:toggle !== false,
39504 scope: editor, // was editor...
39505 handler:handler||editor.relayBtnCmd,
39506 clickEvent:'mousedown',
39507 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39514 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39516 // stop form submits
39517 tb.el.on('click', function(e){
39518 e.preventDefault(); // what does this do?
39521 if(!this.disable.font && !Roo.isSafari){
39522 /* why no safari for fonts
39523 editor.fontSelect = tb.el.createChild({
39526 cls:'x-font-select',
39527 html: editor.createFontOptions()
39529 editor.fontSelect.on('change', function(){
39530 var font = editor.fontSelect.dom.value;
39531 editor.relayCmd('fontname', font);
39532 editor.deferFocus();
39535 editor.fontSelect.dom,
39540 if(!this.disable.formats){
39541 this.formatCombo = new Roo.form.ComboBox({
39542 store: new Roo.data.SimpleStore({
39545 data : this.formats // from states.js
39548 //autoCreate : {tag: "div", size: "20"},
39549 displayField:'tag',
39553 triggerAction: 'all',
39554 emptyText:'Add tag',
39555 selectOnFocus:true,
39558 'select': function(c, r, i) {
39559 editor.insertTag(r.get('tag'));
39565 tb.addField(this.formatCombo);
39569 if(!this.disable.format){
39576 if(!this.disable.fontSize){
39581 btn('increasefontsize', false, editor.adjustFont),
39582 btn('decreasefontsize', false, editor.adjustFont)
39587 if(this.disable.colors){
39590 id:editor.frameId +'-forecolor',
39591 cls:'x-btn-icon x-edit-forecolor',
39592 clickEvent:'mousedown',
39593 tooltip: this.buttonTips['forecolor'] || undefined,
39595 menu : new Roo.menu.ColorMenu({
39596 allowReselect: true,
39597 focus: Roo.emptyFn,
39600 selectHandler: function(cp, color){
39601 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39602 editor.deferFocus();
39605 clickEvent:'mousedown'
39608 id:editor.frameId +'backcolor',
39609 cls:'x-btn-icon x-edit-backcolor',
39610 clickEvent:'mousedown',
39611 tooltip: this.buttonTips['backcolor'] || undefined,
39613 menu : new Roo.menu.ColorMenu({
39614 focus: Roo.emptyFn,
39617 allowReselect: true,
39618 selectHandler: function(cp, color){
39620 editor.execCmd('useCSS', false);
39621 editor.execCmd('hilitecolor', color);
39622 editor.execCmd('useCSS', true);
39623 editor.deferFocus();
39625 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39626 Roo.isSafari || Roo.isIE ? '#'+color : color);
39627 editor.deferFocus();
39631 clickEvent:'mousedown'
39636 // now add all the items...
39639 if(!this.disable.alignments){
39642 btn('justifyleft'),
39643 btn('justifycenter'),
39644 btn('justifyright')
39648 //if(!Roo.isSafari){
39649 if(!this.disable.links){
39652 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39656 if(!this.disable.lists){
39659 btn('insertorderedlist'),
39660 btn('insertunorderedlist')
39663 if(!this.disable.sourceEdit){
39666 btn('sourceedit', true, function(btn){
39667 this.toggleSourceEdit(btn.pressed);
39674 // special menu.. - needs to be tidied up..
39675 if (!this.disable.special) {
39678 cls: 'x-edit-none',
39683 for (var i =0; i < this.specialChars.length; i++) {
39684 smenu.menu.items.push({
39686 html: this.specialChars[i],
39687 handler: function(a,b) {
39688 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39701 for(var i =0; i< this.btns.length;i++) {
39702 var b = this.btns[i];
39703 b.cls = 'x-edit-none';
39712 // disable everything...
39714 this.tb.items.each(function(item){
39715 if(item.id != editor.frameId+ '-sourceedit'){
39719 this.rendered = true;
39721 // the all the btns;
39722 editor.on('editorevent', this.updateToolbar, this);
39723 // other toolbars need to implement this..
39724 //editor.on('editmodechange', this.updateToolbar, this);
39730 * Protected method that will not generally be called directly. It triggers
39731 * a toolbar update by reading the markup state of the current selection in the editor.
39733 updateToolbar: function(){
39735 if(!this.editor.activated){
39736 this.editor.onFirstFocus();
39740 var btns = this.tb.items.map,
39741 doc = this.editor.doc,
39742 frameId = this.editor.frameId;
39744 if(!this.disable.font && !Roo.isSafari){
39746 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39747 if(name != this.fontSelect.dom.value){
39748 this.fontSelect.dom.value = name;
39752 if(!this.disable.format){
39753 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39754 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39755 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39757 if(!this.disable.alignments){
39758 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39759 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39760 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39762 if(!Roo.isSafari && !this.disable.lists){
39763 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39764 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39767 var ans = this.editor.getAllAncestors();
39768 if (this.formatCombo) {
39771 var store = this.formatCombo.store;
39772 this.formatCombo.setValue("");
39773 for (var i =0; i < ans.length;i++) {
39774 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39776 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39784 // hides menus... - so this cant be on a menu...
39785 Roo.menu.MenuMgr.hideAll();
39787 //this.editorsyncValue();
39791 createFontOptions : function(){
39792 var buf = [], fs = this.fontFamilies, ff, lc;
39793 for(var i = 0, len = fs.length; i< len; i++){
39795 lc = ff.toLowerCase();
39797 '<option value="',lc,'" style="font-family:',ff,';"',
39798 (this.defaultFont == lc ? ' selected="true">' : '>'),
39803 return buf.join('');
39806 toggleSourceEdit : function(sourceEditMode){
39807 if(sourceEditMode === undefined){
39808 sourceEditMode = !this.sourceEditMode;
39810 this.sourceEditMode = sourceEditMode === true;
39811 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39812 // just toggle the button?
39813 if(btn.pressed !== this.editor.sourceEditMode){
39814 btn.toggle(this.editor.sourceEditMode);
39818 if(this.sourceEditMode){
39819 this.tb.items.each(function(item){
39820 if(item.cmd != 'sourceedit'){
39826 if(this.initialized){
39827 this.tb.items.each(function(item){
39833 // tell the editor that it's been pressed..
39834 this.editor.toggleSourceEdit(sourceEditMode);
39838 * Object collection of toolbar tooltips for the buttons in the editor. The key
39839 * is the command id associated with that button and the value is a valid QuickTips object.
39844 title: 'Bold (Ctrl+B)',
39845 text: 'Make the selected text bold.',
39846 cls: 'x-html-editor-tip'
39849 title: 'Italic (Ctrl+I)',
39850 text: 'Make the selected text italic.',
39851 cls: 'x-html-editor-tip'
39859 title: 'Bold (Ctrl+B)',
39860 text: 'Make the selected text bold.',
39861 cls: 'x-html-editor-tip'
39864 title: 'Italic (Ctrl+I)',
39865 text: 'Make the selected text italic.',
39866 cls: 'x-html-editor-tip'
39869 title: 'Underline (Ctrl+U)',
39870 text: 'Underline the selected text.',
39871 cls: 'x-html-editor-tip'
39873 increasefontsize : {
39874 title: 'Grow Text',
39875 text: 'Increase the font size.',
39876 cls: 'x-html-editor-tip'
39878 decreasefontsize : {
39879 title: 'Shrink Text',
39880 text: 'Decrease the font size.',
39881 cls: 'x-html-editor-tip'
39884 title: 'Text Highlight Color',
39885 text: 'Change the background color of the selected text.',
39886 cls: 'x-html-editor-tip'
39889 title: 'Font Color',
39890 text: 'Change the color of the selected text.',
39891 cls: 'x-html-editor-tip'
39894 title: 'Align Text Left',
39895 text: 'Align text to the left.',
39896 cls: 'x-html-editor-tip'
39899 title: 'Center Text',
39900 text: 'Center text in the editor.',
39901 cls: 'x-html-editor-tip'
39904 title: 'Align Text Right',
39905 text: 'Align text to the right.',
39906 cls: 'x-html-editor-tip'
39908 insertunorderedlist : {
39909 title: 'Bullet List',
39910 text: 'Start a bulleted list.',
39911 cls: 'x-html-editor-tip'
39913 insertorderedlist : {
39914 title: 'Numbered List',
39915 text: 'Start a numbered list.',
39916 cls: 'x-html-editor-tip'
39919 title: 'Hyperlink',
39920 text: 'Make the selected text a hyperlink.',
39921 cls: 'x-html-editor-tip'
39924 title: 'Source Edit',
39925 text: 'Switch to source editing mode.',
39926 cls: 'x-html-editor-tip'
39930 onDestroy : function(){
39933 this.tb.items.each(function(item){
39935 item.menu.removeAll();
39937 item.menu.el.destroy();
39945 onFirstFocus: function() {
39946 this.tb.items.each(function(item){
39955 // <script type="text/javascript">
39958 * Ext JS Library 1.1.1
39959 * Copyright(c) 2006-2007, Ext JS, LLC.
39966 * @class Roo.form.HtmlEditor.ToolbarContext
39971 new Roo.form.HtmlEditor({
39974 new Roo.form.HtmlEditor.ToolbarStandard(),
39975 new Roo.form.HtmlEditor.ToolbarContext()
39980 * @config : {Object} disable List of elements to disable.. (not done yet.)
39985 Roo.form.HtmlEditor.ToolbarContext = function(config)
39988 Roo.apply(this, config);
39989 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39990 // dont call parent... till later.
39992 Roo.form.HtmlEditor.ToolbarContext.types = {
40004 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40066 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40071 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40135 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40143 * @cfg {Object} disable List of toolbar elements to disable
40152 init : function(editor)
40154 this.editor = editor;
40157 var fid = editor.frameId;
40159 function btn(id, toggle, handler){
40160 var xid = fid + '-'+ id ;
40164 cls : 'x-btn-icon x-edit-'+id,
40165 enableToggle:toggle !== false,
40166 scope: editor, // was editor...
40167 handler:handler||editor.relayBtnCmd,
40168 clickEvent:'mousedown',
40169 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40173 // create a new element.
40174 var wdiv = editor.wrap.createChild({
40176 }, editor.wrap.dom.firstChild.nextSibling, true);
40178 // can we do this more than once??
40180 // stop form submits
40183 // disable everything...
40184 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40185 this.toolbars = {};
40187 for (var i in ty) {
40189 this.toolbars[i] = this.buildToolbar(ty[i],i);
40191 this.tb = this.toolbars.BODY;
40195 this.rendered = true;
40197 // the all the btns;
40198 editor.on('editorevent', this.updateToolbar, this);
40199 // other toolbars need to implement this..
40200 //editor.on('editmodechange', this.updateToolbar, this);
40206 * Protected method that will not generally be called directly. It triggers
40207 * a toolbar update by reading the markup state of the current selection in the editor.
40209 updateToolbar: function(){
40211 if(!this.editor.activated){
40212 this.editor.onFirstFocus();
40217 var ans = this.editor.getAllAncestors();
40220 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40221 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40222 sel = sel ? sel : this.editor.doc.body;
40223 sel = sel.tagName.length ? sel : this.editor.doc.body;
40224 var tn = sel.tagName.toUpperCase();
40225 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40226 tn = sel.tagName.toUpperCase();
40227 if (this.tb.name == tn) {
40228 return; // no change
40231 ///console.log("show: " + tn);
40232 this.tb = this.toolbars[tn];
40234 this.tb.fields.each(function(e) {
40235 e.setValue(sel.getAttribute(e.name));
40237 this.tb.selectedNode = sel;
40240 Roo.menu.MenuMgr.hideAll();
40242 //this.editorsyncValue();
40247 onDestroy : function(){
40250 this.tb.items.each(function(item){
40252 item.menu.removeAll();
40254 item.menu.el.destroy();
40262 onFirstFocus: function() {
40263 // need to do this for all the toolbars..
40264 this.tb.items.each(function(item){
40268 buildToolbar: function(tlist, nm)
40270 var editor = this.editor;
40271 // create a new element.
40272 var wdiv = editor.wrap.createChild({
40274 }, editor.wrap.dom.firstChild.nextSibling, true);
40277 var tb = new Roo.Toolbar(wdiv);
40278 tb.add(nm+ ": ");
40279 for (var i in tlist) {
40280 var item = tlist[i];
40281 tb.add(item.title + ": ");
40286 tb.addField( new Roo.form.ComboBox({
40287 store: new Roo.data.SimpleStore({
40290 data : item.opts // from states.js
40293 displayField:'val',
40297 triggerAction: 'all',
40298 emptyText:'Select',
40299 selectOnFocus:true,
40300 width: item.width ? item.width : 130,
40302 'select': function(c, r, i) {
40303 tb.selectedNode.setAttribute(c.name, r.get('val'));
40314 tb.addField( new Roo.form.TextField({
40317 //allowBlank:false,
40322 tb.addField( new Roo.form.TextField({
40328 'change' : function(f, nv, ov) {
40329 tb.selectedNode.setAttribute(f.name, nv);
40335 tb.el.on('click', function(e){
40336 e.preventDefault(); // what does this do?
40338 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40341 // dont need to disable them... as they will get hidden
40358 * Ext JS Library 1.1.1
40359 * Copyright(c) 2006-2007, Ext JS, LLC.
40361 * Originally Released Under LGPL - original licence link has changed is not relivant.
40364 * <script type="text/javascript">
40368 * @class Roo.form.BasicForm
40369 * @extends Roo.util.Observable
40370 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40372 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40373 * @param {Object} config Configuration options
40375 Roo.form.BasicForm = function(el, config){
40376 this.allItems = [];
40377 this.childForms = [];
40378 Roo.apply(this, config);
40380 * The Roo.form.Field items in this form.
40381 * @type MixedCollection
40385 this.items = new Roo.util.MixedCollection(false, function(o){
40386 return o.id || (o.id = Roo.id());
40390 * @event beforeaction
40391 * Fires before any action is performed. Return false to cancel the action.
40392 * @param {Form} this
40393 * @param {Action} action The action to be performed
40395 beforeaction: true,
40397 * @event actionfailed
40398 * Fires when an action fails.
40399 * @param {Form} this
40400 * @param {Action} action The action that failed
40402 actionfailed : true,
40404 * @event actioncomplete
40405 * Fires when an action is completed.
40406 * @param {Form} this
40407 * @param {Action} action The action that completed
40409 actioncomplete : true
40414 Roo.form.BasicForm.superclass.constructor.call(this);
40417 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40419 * @cfg {String} method
40420 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40423 * @cfg {DataReader} reader
40424 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40425 * This is optional as there is built-in support for processing JSON.
40428 * @cfg {DataReader} errorReader
40429 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40430 * This is completely optional as there is built-in support for processing JSON.
40433 * @cfg {String} url
40434 * The URL to use for form actions if one isn't supplied in the action options.
40437 * @cfg {Boolean} fileUpload
40438 * Set to true if this form is a file upload.
40442 * @cfg {Object} baseParams
40443 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40448 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40453 activeAction : null,
40456 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40457 * or setValues() data instead of when the form was first created.
40459 trackResetOnLoad : false,
40463 * childForms - used for multi-tab forms
40466 childForms : false,
40469 * allItems - full list of fields.
40475 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40476 * element by passing it or its id or mask the form itself by passing in true.
40479 waitMsgTarget : false,
40482 initEl : function(el){
40483 this.el = Roo.get(el);
40484 this.id = this.el.id || Roo.id();
40485 this.el.on('submit', this.onSubmit, this);
40486 this.el.addClass('x-form');
40490 onSubmit : function(e){
40495 * Returns true if client-side validation on the form is successful.
40498 isValid : function(){
40500 this.items.each(function(f){
40509 * Returns true if any fields in this form have changed since their original load.
40512 isDirty : function(){
40514 this.items.each(function(f){
40524 * Performs a predefined action (submit or load) or custom actions you define on this form.
40525 * @param {String} actionName The name of the action type
40526 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40527 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40528 * accept other config options):
40530 Property Type Description
40531 ---------------- --------------- ----------------------------------------------------------------------------------
40532 url String The url for the action (defaults to the form's url)
40533 method String The form method to use (defaults to the form's method, or POST if not defined)
40534 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40535 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40536 validate the form on the client (defaults to false)
40538 * @return {BasicForm} this
40540 doAction : function(action, options){
40541 if(typeof action == 'string'){
40542 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40544 if(this.fireEvent('beforeaction', this, action) !== false){
40545 this.beforeAction(action);
40546 action.run.defer(100, action);
40552 * Shortcut to do a submit action.
40553 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40554 * @return {BasicForm} this
40556 submit : function(options){
40557 this.doAction('submit', options);
40562 * Shortcut to do a load action.
40563 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40564 * @return {BasicForm} this
40566 load : function(options){
40567 this.doAction('load', options);
40572 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40573 * @param {Record} record The record to edit
40574 * @return {BasicForm} this
40576 updateRecord : function(record){
40577 record.beginEdit();
40578 var fs = record.fields;
40579 fs.each(function(f){
40580 var field = this.findField(f.name);
40582 record.set(f.name, field.getValue());
40590 * Loads an Roo.data.Record into this form.
40591 * @param {Record} record The record to load
40592 * @return {BasicForm} this
40594 loadRecord : function(record){
40595 this.setValues(record.data);
40600 beforeAction : function(action){
40601 var o = action.options;
40604 if(this.waitMsgTarget === true){
40605 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40606 }else if(this.waitMsgTarget){
40607 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40608 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40610 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40616 afterAction : function(action, success){
40617 this.activeAction = null;
40618 var o = action.options;
40620 if(this.waitMsgTarget === true){
40622 }else if(this.waitMsgTarget){
40623 this.waitMsgTarget.unmask();
40625 Roo.MessageBox.updateProgress(1);
40626 Roo.MessageBox.hide();
40633 Roo.callback(o.success, o.scope, [this, action]);
40634 this.fireEvent('actioncomplete', this, action);
40637 Roo.callback(o.failure, o.scope, [this, action]);
40638 // show an error message if no failed handler is set..
40639 if (!this.hasListener('actionfailed')) {
40640 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40643 this.fireEvent('actionfailed', this, action);
40649 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40650 * @param {String} id The value to search for
40653 findField : function(id){
40654 var field = this.items.get(id);
40656 this.items.each(function(f){
40657 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40663 return field || null;
40667 * Add a secondary form to this one,
40668 * Used to provide tabbed forms. One form is primary, with hidden values
40669 * which mirror the elements from the other forms.
40671 * @param {Roo.form.Form} form to add.
40674 addForm : function(form)
40677 if (this.childForms.indexOf(form) > -1) {
40681 this.childForms.push(form);
40683 Roo.each(form.allItems, function (fe) {
40685 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40686 if (this.findField(n)) { // already added..
40689 var add = new Roo.form.Hidden({
40692 add.render(this.el);
40699 * Mark fields in this form invalid in bulk.
40700 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40701 * @return {BasicForm} this
40703 markInvalid : function(errors){
40704 if(errors instanceof Array){
40705 for(var i = 0, len = errors.length; i < len; i++){
40706 var fieldError = errors[i];
40707 var f = this.findField(fieldError.id);
40709 f.markInvalid(fieldError.msg);
40715 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40716 field.markInvalid(errors[id]);
40720 Roo.each(this.childForms || [], function (f) {
40721 f.markInvalid(errors);
40728 * Set values for fields in this form in bulk.
40729 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40730 * @return {BasicForm} this
40732 setValues : function(values){
40733 if(values instanceof Array){ // array of objects
40734 for(var i = 0, len = values.length; i < len; i++){
40736 var f = this.findField(v.id);
40738 f.setValue(v.value);
40739 if(this.trackResetOnLoad){
40740 f.originalValue = f.getValue();
40744 }else{ // object hash
40747 if(typeof values[id] != 'function' && (field = this.findField(id))){
40749 if (field.setFromData &&
40750 field.valueField &&
40751 field.displayField &&
40752 // combos' with local stores can
40753 // be queried via setValue()
40754 // to set their value..
40755 (field.store && !field.store.isLocal)
40759 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40760 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40761 field.setFromData(sd);
40764 field.setValue(values[id]);
40768 if(this.trackResetOnLoad){
40769 field.originalValue = field.getValue();
40775 Roo.each(this.childForms || [], function (f) {
40776 f.setValues(values);
40783 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40784 * they are returned as an array.
40785 * @param {Boolean} asString
40788 getValues : function(asString){
40789 if (this.childForms) {
40790 // copy values from the child forms
40791 Roo.each(this.childForms, function (f) {
40792 this.setValues(f.getValues());
40798 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40799 if(asString === true){
40802 return Roo.urlDecode(fs);
40806 * Returns the fields in this form as an object with key/value pairs.
40807 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40810 getFieldValues : function()
40812 if (this.childForms) {
40813 // copy values from the child forms
40814 Roo.each(this.childForms, function (f) {
40815 this.setValues(f.getValues());
40820 this.items.each(function(f){
40821 if (!f.getName()) {
40824 var v = f.getValue();
40825 if ((typeof(v) == 'object') && f.getRawValue) {
40826 v = f.getRawValue() ; // dates..
40828 ret[f.getName()] = v;
40835 * Clears all invalid messages in this form.
40836 * @return {BasicForm} this
40838 clearInvalid : function(){
40839 this.items.each(function(f){
40843 Roo.each(this.childForms || [], function (f) {
40852 * Resets this form.
40853 * @return {BasicForm} this
40855 reset : function(){
40856 this.items.each(function(f){
40860 Roo.each(this.childForms || [], function (f) {
40869 * Add Roo.form components to this form.
40870 * @param {Field} field1
40871 * @param {Field} field2 (optional)
40872 * @param {Field} etc (optional)
40873 * @return {BasicForm} this
40876 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40882 * Removes a field from the items collection (does NOT remove its markup).
40883 * @param {Field} field
40884 * @return {BasicForm} this
40886 remove : function(field){
40887 this.items.remove(field);
40892 * Looks at the fields in this form, checks them for an id attribute,
40893 * and calls applyTo on the existing dom element with that id.
40894 * @return {BasicForm} this
40896 render : function(){
40897 this.items.each(function(f){
40898 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40906 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40907 * @param {Object} values
40908 * @return {BasicForm} this
40910 applyToFields : function(o){
40911 this.items.each(function(f){
40918 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40919 * @param {Object} values
40920 * @return {BasicForm} this
40922 applyIfToFields : function(o){
40923 this.items.each(function(f){
40931 Roo.BasicForm = Roo.form.BasicForm;/*
40933 * Ext JS Library 1.1.1
40934 * Copyright(c) 2006-2007, Ext JS, LLC.
40936 * Originally Released Under LGPL - original licence link has changed is not relivant.
40939 * <script type="text/javascript">
40943 * @class Roo.form.Form
40944 * @extends Roo.form.BasicForm
40945 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40947 * @param {Object} config Configuration options
40949 Roo.form.Form = function(config){
40951 if (config.items) {
40952 xitems = config.items;
40953 delete config.items;
40957 Roo.form.Form.superclass.constructor.call(this, null, config);
40958 this.url = this.url || this.action;
40960 this.root = new Roo.form.Layout(Roo.applyIf({
40964 this.active = this.root;
40966 * Array of all the buttons that have been added to this form via {@link addButton}
40970 this.allItems = [];
40973 * @event clientvalidation
40974 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40975 * @param {Form} this
40976 * @param {Boolean} valid true if the form has passed client-side validation
40978 clientvalidation: true,
40981 * Fires when the form is rendered
40982 * @param {Roo.form.Form} form
40987 if (this.progressUrl) {
40988 // push a hidden field onto the list of fields..
40992 name : 'UPLOAD_IDENTIFIER'
40997 Roo.each(xitems, this.addxtype, this);
41003 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41005 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41008 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41011 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41013 buttonAlign:'center',
41016 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41021 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41022 * This property cascades to child containers if not set.
41027 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41028 * fires a looping event with that state. This is required to bind buttons to the valid
41029 * state using the config value formBind:true on the button.
41031 monitorValid : false,
41034 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41039 * @cfg {String} progressUrl - Url to return progress data
41042 progressUrl : false,
41045 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41046 * fields are added and the column is closed. If no fields are passed the column remains open
41047 * until end() is called.
41048 * @param {Object} config The config to pass to the column
41049 * @param {Field} field1 (optional)
41050 * @param {Field} field2 (optional)
41051 * @param {Field} etc (optional)
41052 * @return Column The column container object
41054 column : function(c){
41055 var col = new Roo.form.Column(c);
41057 if(arguments.length > 1){ // duplicate code required because of Opera
41058 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41065 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41066 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41067 * until end() is called.
41068 * @param {Object} config The config to pass to the fieldset
41069 * @param {Field} field1 (optional)
41070 * @param {Field} field2 (optional)
41071 * @param {Field} etc (optional)
41072 * @return FieldSet The fieldset container object
41074 fieldset : function(c){
41075 var fs = new Roo.form.FieldSet(c);
41077 if(arguments.length > 1){ // duplicate code required because of Opera
41078 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41085 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41086 * fields are added and the container is closed. If no fields are passed the container remains open
41087 * until end() is called.
41088 * @param {Object} config The config to pass to the Layout
41089 * @param {Field} field1 (optional)
41090 * @param {Field} field2 (optional)
41091 * @param {Field} etc (optional)
41092 * @return Layout The container object
41094 container : function(c){
41095 var l = new Roo.form.Layout(c);
41097 if(arguments.length > 1){ // duplicate code required because of Opera
41098 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41105 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41106 * @param {Object} container A Roo.form.Layout or subclass of Layout
41107 * @return {Form} this
41109 start : function(c){
41110 // cascade label info
41111 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41112 this.active.stack.push(c);
41113 c.ownerCt = this.active;
41119 * Closes the current open container
41120 * @return {Form} this
41123 if(this.active == this.root){
41126 this.active = this.active.ownerCt;
41131 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41132 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41133 * as the label of the field.
41134 * @param {Field} field1
41135 * @param {Field} field2 (optional)
41136 * @param {Field} etc. (optional)
41137 * @return {Form} this
41140 this.active.stack.push.apply(this.active.stack, arguments);
41141 this.allItems.push.apply(this.allItems,arguments);
41143 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41144 if(a[i].isFormField){
41149 Roo.form.Form.superclass.add.apply(this, r);
41159 * Find any element that has been added to a form, using it's ID or name
41160 * This can include framesets, columns etc. along with regular fields..
41161 * @param {String} id - id or name to find.
41163 * @return {Element} e - or false if nothing found.
41165 findbyId : function(id)
41171 Ext.each(this.allItems, function(f){
41172 if (f.id == id || f.name == id ){
41183 * Render this form into the passed container. This should only be called once!
41184 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41185 * @return {Form} this
41187 render : function(ct)
41193 var o = this.autoCreate || {
41195 method : this.method || 'POST',
41196 id : this.id || Roo.id()
41198 this.initEl(ct.createChild(o));
41200 this.root.render(this.el);
41204 this.items.each(function(f){
41205 f.render('x-form-el-'+f.id);
41208 if(this.buttons.length > 0){
41209 // tables are required to maintain order and for correct IE layout
41210 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41211 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41212 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41214 var tr = tb.getElementsByTagName('tr')[0];
41215 for(var i = 0, len = this.buttons.length; i < len; i++) {
41216 var b = this.buttons[i];
41217 var td = document.createElement('td');
41218 td.className = 'x-form-btn-td';
41219 b.render(tr.appendChild(td));
41222 if(this.monitorValid){ // initialize after render
41223 this.startMonitoring();
41225 this.fireEvent('rendered', this);
41230 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41231 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41232 * object or a valid Roo.DomHelper element config
41233 * @param {Function} handler The function called when the button is clicked
41234 * @param {Object} scope (optional) The scope of the handler function
41235 * @return {Roo.Button}
41237 addButton : function(config, handler, scope){
41241 minWidth: this.minButtonWidth,
41244 if(typeof config == "string"){
41247 Roo.apply(bc, config);
41249 var btn = new Roo.Button(null, bc);
41250 this.buttons.push(btn);
41255 * Adds a series of form elements (using the xtype property as the factory method.
41256 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41257 * @param {Object} config
41260 addxtype : function()
41262 var ar = Array.prototype.slice.call(arguments, 0);
41264 for(var i = 0; i < ar.length; i++) {
41266 continue; // skip -- if this happends something invalid got sent, we
41267 // should ignore it, as basically that interface element will not show up
41268 // and that should be pretty obvious!!
41271 if (Roo.form[ar[i].xtype]) {
41273 var fe = Roo.factory(ar[i], Roo.form);
41279 fe.store.form = this;
41284 this.allItems.push(fe);
41285 if (fe.items && fe.addxtype) {
41286 fe.addxtype.apply(fe, fe.items);
41296 // console.log('adding ' + ar[i].xtype);
41298 if (ar[i].xtype == 'Button') {
41299 //console.log('adding button');
41300 //console.log(ar[i]);
41301 this.addButton(ar[i]);
41302 this.allItems.push(fe);
41306 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41307 alert('end is not supported on xtype any more, use items');
41309 // //console.log('adding end');
41317 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41318 * option "monitorValid"
41320 startMonitoring : function(){
41323 Roo.TaskMgr.start({
41324 run : this.bindHandler,
41325 interval : this.monitorPoll || 200,
41332 * Stops monitoring of the valid state of this form
41334 stopMonitoring : function(){
41335 this.bound = false;
41339 bindHandler : function(){
41341 return false; // stops binding
41344 this.items.each(function(f){
41345 if(!f.isValid(true)){
41350 for(var i = 0, len = this.buttons.length; i < len; i++){
41351 var btn = this.buttons[i];
41352 if(btn.formBind === true && btn.disabled === valid){
41353 btn.setDisabled(!valid);
41356 this.fireEvent('clientvalidation', this, valid);
41370 Roo.Form = Roo.form.Form;
41373 * Ext JS Library 1.1.1
41374 * Copyright(c) 2006-2007, Ext JS, LLC.
41376 * Originally Released Under LGPL - original licence link has changed is not relivant.
41379 * <script type="text/javascript">
41383 * @class Roo.form.Action
41384 * Internal Class used to handle form actions
41386 * @param {Roo.form.BasicForm} el The form element or its id
41387 * @param {Object} config Configuration options
41391 // define the action interface
41392 Roo.form.Action = function(form, options){
41394 this.options = options || {};
41397 * Client Validation Failed
41400 Roo.form.Action.CLIENT_INVALID = 'client';
41402 * Server Validation Failed
41405 Roo.form.Action.SERVER_INVALID = 'server';
41407 * Connect to Server Failed
41410 Roo.form.Action.CONNECT_FAILURE = 'connect';
41412 * Reading Data from Server Failed
41415 Roo.form.Action.LOAD_FAILURE = 'load';
41417 Roo.form.Action.prototype = {
41419 failureType : undefined,
41420 response : undefined,
41421 result : undefined,
41423 // interface method
41424 run : function(options){
41428 // interface method
41429 success : function(response){
41433 // interface method
41434 handleResponse : function(response){
41438 // default connection failure
41439 failure : function(response){
41441 this.response = response;
41442 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41443 this.form.afterAction(this, false);
41446 processResponse : function(response){
41447 this.response = response;
41448 if(!response.responseText){
41451 this.result = this.handleResponse(response);
41452 return this.result;
41455 // utility functions used internally
41456 getUrl : function(appendParams){
41457 var url = this.options.url || this.form.url || this.form.el.dom.action;
41459 var p = this.getParams();
41461 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41467 getMethod : function(){
41468 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41471 getParams : function(){
41472 var bp = this.form.baseParams;
41473 var p = this.options.params;
41475 if(typeof p == "object"){
41476 p = Roo.urlEncode(Roo.applyIf(p, bp));
41477 }else if(typeof p == 'string' && bp){
41478 p += '&' + Roo.urlEncode(bp);
41481 p = Roo.urlEncode(bp);
41486 createCallback : function(){
41488 success: this.success,
41489 failure: this.failure,
41491 timeout: (this.form.timeout*1000),
41492 upload: this.form.fileUpload ? this.success : undefined
41497 Roo.form.Action.Submit = function(form, options){
41498 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41501 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41504 haveProgress : false,
41505 uploadComplete : false,
41507 // uploadProgress indicator.
41508 uploadProgress : function()
41510 if (!this.form.progressUrl) {
41514 if (!this.haveProgress) {
41515 Roo.MessageBox.progress("Uploading", "Uploading");
41517 if (this.uploadComplete) {
41518 Roo.MessageBox.hide();
41522 this.haveProgress = true;
41524 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41526 var c = new Roo.data.Connection();
41528 url : this.form.progressUrl,
41533 success : function(req){
41534 //console.log(data);
41538 rdata = Roo.decode(req.responseText)
41540 Roo.log("Invalid data from server..");
41544 if (!rdata || !rdata.success) {
41548 var data = rdata.data;
41550 if (this.uploadComplete) {
41551 Roo.MessageBox.hide();
41556 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41557 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41560 this.uploadProgress.defer(2000,this);
41563 failure: function(data) {
41564 Roo.log('progress url failed ');
41575 // run get Values on the form, so it syncs any secondary forms.
41576 this.form.getValues();
41578 var o = this.options;
41579 var method = this.getMethod();
41580 var isPost = method == 'POST';
41581 if(o.clientValidation === false || this.form.isValid()){
41583 if (this.form.progressUrl) {
41584 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41585 (new Date() * 1) + '' + Math.random());
41590 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41591 form:this.form.el.dom,
41592 url:this.getUrl(!isPost),
41594 params:isPost ? this.getParams() : null,
41595 isUpload: this.form.fileUpload
41598 this.uploadProgress();
41600 }else if (o.clientValidation !== false){ // client validation failed
41601 this.failureType = Roo.form.Action.CLIENT_INVALID;
41602 this.form.afterAction(this, false);
41606 success : function(response)
41608 this.uploadComplete= true;
41609 if (this.haveProgress) {
41610 Roo.MessageBox.hide();
41614 var result = this.processResponse(response);
41615 if(result === true || result.success){
41616 this.form.afterAction(this, true);
41620 this.form.markInvalid(result.errors);
41621 this.failureType = Roo.form.Action.SERVER_INVALID;
41623 this.form.afterAction(this, false);
41625 failure : function(response)
41627 this.uploadComplete= true;
41628 if (this.haveProgress) {
41629 Roo.MessageBox.hide();
41633 this.response = response;
41634 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41635 this.form.afterAction(this, false);
41638 handleResponse : function(response){
41639 if(this.form.errorReader){
41640 var rs = this.form.errorReader.read(response);
41643 for(var i = 0, len = rs.records.length; i < len; i++) {
41644 var r = rs.records[i];
41645 errors[i] = r.data;
41648 if(errors.length < 1){
41652 success : rs.success,
41658 ret = Roo.decode(response.responseText);
41662 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41672 Roo.form.Action.Load = function(form, options){
41673 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41674 this.reader = this.form.reader;
41677 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41682 Roo.Ajax.request(Roo.apply(
41683 this.createCallback(), {
41684 method:this.getMethod(),
41685 url:this.getUrl(false),
41686 params:this.getParams()
41690 success : function(response){
41692 var result = this.processResponse(response);
41693 if(result === true || !result.success || !result.data){
41694 this.failureType = Roo.form.Action.LOAD_FAILURE;
41695 this.form.afterAction(this, false);
41698 this.form.clearInvalid();
41699 this.form.setValues(result.data);
41700 this.form.afterAction(this, true);
41703 handleResponse : function(response){
41704 if(this.form.reader){
41705 var rs = this.form.reader.read(response);
41706 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41708 success : rs.success,
41712 return Roo.decode(response.responseText);
41716 Roo.form.Action.ACTION_TYPES = {
41717 'load' : Roo.form.Action.Load,
41718 'submit' : Roo.form.Action.Submit
41721 * Ext JS Library 1.1.1
41722 * Copyright(c) 2006-2007, Ext JS, LLC.
41724 * Originally Released Under LGPL - original licence link has changed is not relivant.
41727 * <script type="text/javascript">
41731 * @class Roo.form.Layout
41732 * @extends Roo.Component
41733 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41735 * @param {Object} config Configuration options
41737 Roo.form.Layout = function(config){
41739 if (config.items) {
41740 xitems = config.items;
41741 delete config.items;
41743 Roo.form.Layout.superclass.constructor.call(this, config);
41745 Roo.each(xitems, this.addxtype, this);
41749 Roo.extend(Roo.form.Layout, Roo.Component, {
41751 * @cfg {String/Object} autoCreate
41752 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41755 * @cfg {String/Object/Function} style
41756 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41757 * a function which returns such a specification.
41760 * @cfg {String} labelAlign
41761 * Valid values are "left," "top" and "right" (defaults to "left")
41764 * @cfg {Number} labelWidth
41765 * Fixed width in pixels of all field labels (defaults to undefined)
41768 * @cfg {Boolean} clear
41769 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41773 * @cfg {String} labelSeparator
41774 * The separator to use after field labels (defaults to ':')
41776 labelSeparator : ':',
41778 * @cfg {Boolean} hideLabels
41779 * True to suppress the display of field labels in this layout (defaults to false)
41781 hideLabels : false,
41784 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41789 onRender : function(ct, position){
41790 if(this.el){ // from markup
41791 this.el = Roo.get(this.el);
41792 }else { // generate
41793 var cfg = this.getAutoCreate();
41794 this.el = ct.createChild(cfg, position);
41797 this.el.applyStyles(this.style);
41799 if(this.labelAlign){
41800 this.el.addClass('x-form-label-'+this.labelAlign);
41802 if(this.hideLabels){
41803 this.labelStyle = "display:none";
41804 this.elementStyle = "padding-left:0;";
41806 if(typeof this.labelWidth == 'number'){
41807 this.labelStyle = "width:"+this.labelWidth+"px;";
41808 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41810 if(this.labelAlign == 'top'){
41811 this.labelStyle = "width:auto;";
41812 this.elementStyle = "padding-left:0;";
41815 var stack = this.stack;
41816 var slen = stack.length;
41818 if(!this.fieldTpl){
41819 var t = new Roo.Template(
41820 '<div class="x-form-item {5}">',
41821 '<label for="{0}" style="{2}">{1}{4}</label>',
41822 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41824 '</div><div class="x-form-clear-left"></div>'
41826 t.disableFormats = true;
41828 Roo.form.Layout.prototype.fieldTpl = t;
41830 for(var i = 0; i < slen; i++) {
41831 if(stack[i].isFormField){
41832 this.renderField(stack[i]);
41834 this.renderComponent(stack[i]);
41839 this.el.createChild({cls:'x-form-clear'});
41844 renderField : function(f){
41845 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41848 f.labelStyle||this.labelStyle||'', //2
41849 this.elementStyle||'', //3
41850 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41851 f.itemCls||this.itemCls||'' //5
41852 ], true).getPrevSibling());
41856 renderComponent : function(c){
41857 c.render(c.isLayout ? this.el : this.el.createChild());
41860 * Adds a object form elements (using the xtype property as the factory method.)
41861 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41862 * @param {Object} config
41864 addxtype : function(o)
41866 // create the lement.
41867 o.form = this.form;
41868 var fe = Roo.factory(o, Roo.form);
41869 this.form.allItems.push(fe);
41870 this.stack.push(fe);
41872 if (fe.isFormField) {
41873 this.form.items.add(fe);
41881 * @class Roo.form.Column
41882 * @extends Roo.form.Layout
41883 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41885 * @param {Object} config Configuration options
41887 Roo.form.Column = function(config){
41888 Roo.form.Column.superclass.constructor.call(this, config);
41891 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41893 * @cfg {Number/String} width
41894 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41897 * @cfg {String/Object} autoCreate
41898 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41902 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41905 onRender : function(ct, position){
41906 Roo.form.Column.superclass.onRender.call(this, ct, position);
41908 this.el.setWidth(this.width);
41915 * @class Roo.form.Row
41916 * @extends Roo.form.Layout
41917 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41919 * @param {Object} config Configuration options
41923 Roo.form.Row = function(config){
41924 Roo.form.Row.superclass.constructor.call(this, config);
41927 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41929 * @cfg {Number/String} width
41930 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41933 * @cfg {Number/String} height
41934 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41936 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41940 onRender : function(ct, position){
41941 //console.log('row render');
41943 var t = new Roo.Template(
41944 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41945 '<label for="{0}" style="{2}">{1}{4}</label>',
41946 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41950 t.disableFormats = true;
41952 Roo.form.Layout.prototype.rowTpl = t;
41954 this.fieldTpl = this.rowTpl;
41956 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41957 var labelWidth = 100;
41959 if ((this.labelAlign != 'top')) {
41960 if (typeof this.labelWidth == 'number') {
41961 labelWidth = this.labelWidth
41963 this.padWidth = 20 + labelWidth;
41967 Roo.form.Column.superclass.onRender.call(this, ct, position);
41969 this.el.setWidth(this.width);
41972 this.el.setHeight(this.height);
41977 renderField : function(f){
41978 f.fieldEl = this.fieldTpl.append(this.el, [
41979 f.id, f.fieldLabel,
41980 f.labelStyle||this.labelStyle||'',
41981 this.elementStyle||'',
41982 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41983 f.itemCls||this.itemCls||'',
41984 f.width ? f.width + this.padWidth : 160 + this.padWidth
41991 * @class Roo.form.FieldSet
41992 * @extends Roo.form.Layout
41993 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41995 * @param {Object} config Configuration options
41997 Roo.form.FieldSet = function(config){
41998 Roo.form.FieldSet.superclass.constructor.call(this, config);
42001 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42003 * @cfg {String} legend
42004 * The text to display as the legend for the FieldSet (defaults to '')
42007 * @cfg {String/Object} autoCreate
42008 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42012 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42015 onRender : function(ct, position){
42016 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42018 this.setLegend(this.legend);
42023 setLegend : function(text){
42025 this.el.child('legend').update(text);
42030 * Ext JS Library 1.1.1
42031 * Copyright(c) 2006-2007, Ext JS, LLC.
42033 * Originally Released Under LGPL - original licence link has changed is not relivant.
42036 * <script type="text/javascript">
42039 * @class Roo.form.VTypes
42040 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42043 Roo.form.VTypes = function(){
42044 // closure these in so they are only created once.
42045 var alpha = /^[a-zA-Z_]+$/;
42046 var alphanum = /^[a-zA-Z0-9_]+$/;
42047 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42048 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42050 // All these messages and functions are configurable
42053 * The function used to validate email addresses
42054 * @param {String} value The email address
42056 'email' : function(v){
42057 return email.test(v);
42060 * The error text to display when the email validation function returns false
42063 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42065 * The keystroke filter mask to be applied on email input
42068 'emailMask' : /[a-z0-9_\.\-@]/i,
42071 * The function used to validate URLs
42072 * @param {String} value The URL
42074 'url' : function(v){
42075 return url.test(v);
42078 * The error text to display when the url validation function returns false
42081 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42084 * The function used to validate alpha values
42085 * @param {String} value The value
42087 'alpha' : function(v){
42088 return alpha.test(v);
42091 * The error text to display when the alpha validation function returns false
42094 'alphaText' : 'This field should only contain letters and _',
42096 * The keystroke filter mask to be applied on alpha input
42099 'alphaMask' : /[a-z_]/i,
42102 * The function used to validate alphanumeric values
42103 * @param {String} value The value
42105 'alphanum' : function(v){
42106 return alphanum.test(v);
42109 * The error text to display when the alphanumeric validation function returns false
42112 'alphanumText' : 'This field should only contain letters, numbers and _',
42114 * The keystroke filter mask to be applied on alphanumeric input
42117 'alphanumMask' : /[a-z0-9_]/i
42119 }();//<script type="text/javascript">
42122 * @class Roo.form.FCKeditor
42123 * @extends Roo.form.TextArea
42124 * Wrapper around the FCKEditor http://www.fckeditor.net
42126 * Creates a new FCKeditor
42127 * @param {Object} config Configuration options
42129 Roo.form.FCKeditor = function(config){
42130 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42133 * @event editorinit
42134 * Fired when the editor is initialized - you can add extra handlers here..
42135 * @param {FCKeditor} this
42136 * @param {Object} the FCK object.
42143 Roo.form.FCKeditor.editors = { };
42144 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42146 //defaultAutoCreate : {
42147 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42151 * @cfg {Object} fck options - see fck manual for details.
42156 * @cfg {Object} fck toolbar set (Basic or Default)
42158 toolbarSet : 'Basic',
42160 * @cfg {Object} fck BasePath
42162 basePath : '/fckeditor/',
42170 onRender : function(ct, position)
42173 this.defaultAutoCreate = {
42175 style:"width:300px;height:60px;",
42176 autocomplete: "off"
42179 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42182 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42183 if(this.preventScrollbars){
42184 this.el.setStyle("overflow", "hidden");
42186 this.el.setHeight(this.growMin);
42189 //console.log('onrender' + this.getId() );
42190 Roo.form.FCKeditor.editors[this.getId()] = this;
42193 this.replaceTextarea() ;
42197 getEditor : function() {
42198 return this.fckEditor;
42201 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42202 * @param {Mixed} value The value to set
42206 setValue : function(value)
42208 //console.log('setValue: ' + value);
42210 if(typeof(value) == 'undefined') { // not sure why this is happending...
42213 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42215 //if(!this.el || !this.getEditor()) {
42216 // this.value = value;
42217 //this.setValue.defer(100,this,[value]);
42221 if(!this.getEditor()) {
42225 this.getEditor().SetData(value);
42232 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42233 * @return {Mixed} value The field value
42235 getValue : function()
42238 if (this.frame && this.frame.dom.style.display == 'none') {
42239 return Roo.form.FCKeditor.superclass.getValue.call(this);
42242 if(!this.el || !this.getEditor()) {
42244 // this.getValue.defer(100,this);
42249 var value=this.getEditor().GetData();
42250 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42251 return Roo.form.FCKeditor.superclass.getValue.call(this);
42257 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42258 * @return {Mixed} value The field value
42260 getRawValue : function()
42262 if (this.frame && this.frame.dom.style.display == 'none') {
42263 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42266 if(!this.el || !this.getEditor()) {
42267 //this.getRawValue.defer(100,this);
42274 var value=this.getEditor().GetData();
42275 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42276 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42280 setSize : function(w,h) {
42284 //if (this.frame && this.frame.dom.style.display == 'none') {
42285 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42288 //if(!this.el || !this.getEditor()) {
42289 // this.setSize.defer(100,this, [w,h]);
42295 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42297 this.frame.dom.setAttribute('width', w);
42298 this.frame.dom.setAttribute('height', h);
42299 this.frame.setSize(w,h);
42303 toggleSourceEdit : function(value) {
42307 this.el.dom.style.display = value ? '' : 'none';
42308 this.frame.dom.style.display = value ? 'none' : '';
42313 focus: function(tag)
42315 if (this.frame.dom.style.display == 'none') {
42316 return Roo.form.FCKeditor.superclass.focus.call(this);
42318 if(!this.el || !this.getEditor()) {
42319 this.focus.defer(100,this, [tag]);
42326 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42327 this.getEditor().Focus();
42329 if (!this.getEditor().Selection.GetSelection()) {
42330 this.focus.defer(100,this, [tag]);
42335 var r = this.getEditor().EditorDocument.createRange();
42336 r.setStart(tgs[0],0);
42337 r.setEnd(tgs[0],0);
42338 this.getEditor().Selection.GetSelection().removeAllRanges();
42339 this.getEditor().Selection.GetSelection().addRange(r);
42340 this.getEditor().Focus();
42347 replaceTextarea : function()
42349 if ( document.getElementById( this.getId() + '___Frame' ) )
42351 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42353 // We must check the elements firstly using the Id and then the name.
42354 var oTextarea = document.getElementById( this.getId() );
42356 var colElementsByName = document.getElementsByName( this.getId() ) ;
42358 oTextarea.style.display = 'none' ;
42360 if ( oTextarea.tabIndex ) {
42361 this.TabIndex = oTextarea.tabIndex ;
42364 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42365 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42366 this.frame = Roo.get(this.getId() + '___Frame')
42369 _getConfigHtml : function()
42373 for ( var o in this.fckconfig ) {
42374 sConfig += sConfig.length > 0 ? '&' : '';
42375 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42378 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42382 _getIFrameHtml : function()
42384 var sFile = 'fckeditor.html' ;
42385 /* no idea what this is about..
42388 if ( (/fcksource=true/i).test( window.top.location.search ) )
42389 sFile = 'fckeditor.original.html' ;
42394 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42395 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42398 var html = '<iframe id="' + this.getId() +
42399 '___Frame" src="' + sLink +
42400 '" width="' + this.width +
42401 '" height="' + this.height + '"' +
42402 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42403 ' frameborder="0" scrolling="no"></iframe>' ;
42408 _insertHtmlBefore : function( html, element )
42410 if ( element.insertAdjacentHTML ) {
42412 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42414 var oRange = document.createRange() ;
42415 oRange.setStartBefore( element ) ;
42416 var oFragment = oRange.createContextualFragment( html );
42417 element.parentNode.insertBefore( oFragment, element ) ;
42430 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42432 function FCKeditor_OnComplete(editorInstance){
42433 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42434 f.fckEditor = editorInstance;
42435 //console.log("loaded");
42436 f.fireEvent('editorinit', f, editorInstance);
42456 //<script type="text/javascript">
42458 * @class Roo.form.GridField
42459 * @extends Roo.form.Field
42460 * Embed a grid (or editable grid into a form)
42463 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42465 * xgrid.store = Roo.data.Store
42466 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42467 * xgrid.store.reader = Roo.data.JsonReader
42471 * Creates a new GridField
42472 * @param {Object} config Configuration options
42474 Roo.form.GridField = function(config){
42475 Roo.form.GridField.superclass.constructor.call(this, config);
42479 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42481 * @cfg {Number} width - used to restrict width of grid..
42485 * @cfg {Number} height - used to restrict height of grid..
42489 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42495 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42496 * {tag: "input", type: "checkbox", autocomplete: "off"})
42498 // defaultAutoCreate : { tag: 'div' },
42499 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42501 * @cfg {String} addTitle Text to include for adding a title.
42505 onResize : function(){
42506 Roo.form.Field.superclass.onResize.apply(this, arguments);
42509 initEvents : function(){
42510 // Roo.form.Checkbox.superclass.initEvents.call(this);
42511 // has no events...
42516 getResizeEl : function(){
42520 getPositionEl : function(){
42525 onRender : function(ct, position){
42527 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42528 var style = this.style;
42531 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42532 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42533 this.viewEl = this.wrap.createChild({ tag: 'div' });
42535 this.viewEl.applyStyles(style);
42538 this.viewEl.setWidth(this.width);
42541 this.viewEl.setHeight(this.height);
42543 //if(this.inputValue !== undefined){
42544 //this.setValue(this.value);
42547 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42550 this.grid.render();
42551 this.grid.getDataSource().on('remove', this.refreshValue, this);
42552 this.grid.getDataSource().on('update', this.refreshValue, this);
42553 this.grid.on('afteredit', this.refreshValue, this);
42559 * Sets the value of the item.
42560 * @param {String} either an object or a string..
42562 setValue : function(v){
42564 v = v || []; // empty set..
42565 // this does not seem smart - it really only affects memoryproxy grids..
42566 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42567 var ds = this.grid.getDataSource();
42568 // assumes a json reader..
42570 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42571 ds.loadData( data);
42573 Roo.form.GridField.superclass.setValue.call(this, v);
42574 this.refreshValue();
42575 // should load data in the grid really....
42579 refreshValue: function() {
42581 this.grid.getDataSource().each(function(r) {
42584 this.el.dom.value = Roo.encode(val);
42592 * Ext JS Library 1.1.1
42593 * Copyright(c) 2006-2007, Ext JS, LLC.
42595 * Originally Released Under LGPL - original licence link has changed is not relivant.
42598 * <script type="text/javascript">
42601 * @class Roo.form.DisplayField
42602 * @extends Roo.form.Field
42603 * A generic Field to display non-editable data.
42605 * Creates a new Display Field item.
42606 * @param {Object} config Configuration options
42608 Roo.form.DisplayField = function(config){
42609 Roo.form.DisplayField.superclass.constructor.call(this, config);
42613 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42614 inputType: 'hidden',
42620 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42622 focusClass : undefined,
42624 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42626 fieldClass: 'x-form-field',
42629 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42631 valueRenderer: undefined,
42635 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42636 * {tag: "input", type: "checkbox", autocomplete: "off"})
42639 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42641 onResize : function(){
42642 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42646 initEvents : function(){
42647 // Roo.form.Checkbox.superclass.initEvents.call(this);
42648 // has no events...
42653 getResizeEl : function(){
42657 getPositionEl : function(){
42662 onRender : function(ct, position){
42664 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42665 //if(this.inputValue !== undefined){
42666 this.wrap = this.el.wrap();
42668 this.viewEl = this.wrap.createChild({ tag: 'div'});
42670 if (this.bodyStyle) {
42671 this.viewEl.applyStyles(this.bodyStyle);
42673 //this.viewEl.setStyle('padding', '2px');
42675 this.setValue(this.value);
42680 initValue : Roo.emptyFn,
42685 onClick : function(){
42690 * Sets the checked state of the checkbox.
42691 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42693 setValue : function(v){
42695 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42696 // this might be called before we have a dom element..
42697 if (!this.viewEl) {
42700 this.viewEl.dom.innerHTML = html;
42701 Roo.form.DisplayField.superclass.setValue.call(this, v);
42704 });//<script type="text/javasscript">
42708 * @class Roo.DDView
42709 * A DnD enabled version of Roo.View.
42710 * @param {Element/String} container The Element in which to create the View.
42711 * @param {String} tpl The template string used to create the markup for each element of the View
42712 * @param {Object} config The configuration properties. These include all the config options of
42713 * {@link Roo.View} plus some specific to this class.<br>
42715 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42716 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42718 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42719 .x-view-drag-insert-above {
42720 border-top:1px dotted #3366cc;
42722 .x-view-drag-insert-below {
42723 border-bottom:1px dotted #3366cc;
42729 Roo.DDView = function(container, tpl, config) {
42730 Roo.DDView.superclass.constructor.apply(this, arguments);
42731 this.getEl().setStyle("outline", "0px none");
42732 this.getEl().unselectable();
42733 if (this.dragGroup) {
42734 this.setDraggable(this.dragGroup.split(","));
42736 if (this.dropGroup) {
42737 this.setDroppable(this.dropGroup.split(","));
42739 if (this.deletable) {
42740 this.setDeletable();
42742 this.isDirtyFlag = false;
42748 Roo.extend(Roo.DDView, Roo.View, {
42749 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42750 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42751 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42752 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42756 reset: Roo.emptyFn,
42758 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42760 validate: function() {
42764 destroy: function() {
42765 this.purgeListeners();
42766 this.getEl.removeAllListeners();
42767 this.getEl().remove();
42768 if (this.dragZone) {
42769 if (this.dragZone.destroy) {
42770 this.dragZone.destroy();
42773 if (this.dropZone) {
42774 if (this.dropZone.destroy) {
42775 this.dropZone.destroy();
42780 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42781 getName: function() {
42785 /** Loads the View from a JSON string representing the Records to put into the Store. */
42786 setValue: function(v) {
42788 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42791 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42792 this.store.proxy = new Roo.data.MemoryProxy(data);
42796 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42797 getValue: function() {
42799 this.store.each(function(rec) {
42800 result += rec.id + ',';
42802 return result.substr(0, result.length - 1) + ')';
42805 getIds: function() {
42806 var i = 0, result = new Array(this.store.getCount());
42807 this.store.each(function(rec) {
42808 result[i++] = rec.id;
42813 isDirty: function() {
42814 return this.isDirtyFlag;
42818 * Part of the Roo.dd.DropZone interface. If no target node is found, the
42819 * whole Element becomes the target, and this causes the drop gesture to append.
42821 getTargetFromEvent : function(e) {
42822 var target = e.getTarget();
42823 while ((target !== null) && (target.parentNode != this.el.dom)) {
42824 target = target.parentNode;
42827 target = this.el.dom.lastChild || this.el.dom;
42833 * Create the drag data which consists of an object which has the property "ddel" as
42834 * the drag proxy element.
42836 getDragData : function(e) {
42837 var target = this.findItemFromChild(e.getTarget());
42839 this.handleSelection(e);
42840 var selNodes = this.getSelectedNodes();
42843 copy: this.copy || (this.allowCopy && e.ctrlKey),
42847 var selectedIndices = this.getSelectedIndexes();
42848 for (var i = 0; i < selectedIndices.length; i++) {
42849 dragData.records.push(this.store.getAt(selectedIndices[i]));
42851 if (selNodes.length == 1) {
42852 dragData.ddel = target.cloneNode(true); // the div element
42854 var div = document.createElement('div'); // create the multi element drag "ghost"
42855 div.className = 'multi-proxy';
42856 for (var i = 0, len = selNodes.length; i < len; i++) {
42857 div.appendChild(selNodes[i].cloneNode(true));
42859 dragData.ddel = div;
42861 //console.log(dragData)
42862 //console.log(dragData.ddel.innerHTML)
42865 //console.log('nodragData')
42869 /** Specify to which ddGroup items in this DDView may be dragged. */
42870 setDraggable: function(ddGroup) {
42871 if (ddGroup instanceof Array) {
42872 Roo.each(ddGroup, this.setDraggable, this);
42875 if (this.dragZone) {
42876 this.dragZone.addToGroup(ddGroup);
42878 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
42879 containerScroll: true,
42883 // Draggability implies selection. DragZone's mousedown selects the element.
42884 if (!this.multiSelect) { this.singleSelect = true; }
42886 // Wire the DragZone's handlers up to methods in *this*
42887 this.dragZone.getDragData = this.getDragData.createDelegate(this);
42891 /** Specify from which ddGroup this DDView accepts drops. */
42892 setDroppable: function(ddGroup) {
42893 if (ddGroup instanceof Array) {
42894 Roo.each(ddGroup, this.setDroppable, this);
42897 if (this.dropZone) {
42898 this.dropZone.addToGroup(ddGroup);
42900 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
42901 containerScroll: true,
42905 // Wire the DropZone's handlers up to methods in *this*
42906 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42907 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42908 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42909 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42910 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42914 /** Decide whether to drop above or below a View node. */
42915 getDropPoint : function(e, n, dd){
42916 if (n == this.el.dom) { return "above"; }
42917 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42918 var c = t + (b - t) / 2;
42919 var y = Roo.lib.Event.getPageY(e);
42927 onNodeEnter : function(n, dd, e, data){
42931 onNodeOver : function(n, dd, e, data){
42932 var pt = this.getDropPoint(e, n, dd);
42933 // set the insert point style on the target node
42934 var dragElClass = this.dropNotAllowed;
42937 if (pt == "above"){
42938 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42939 targetElClass = "x-view-drag-insert-above";
42941 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42942 targetElClass = "x-view-drag-insert-below";
42944 if (this.lastInsertClass != targetElClass){
42945 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42946 this.lastInsertClass = targetElClass;
42949 return dragElClass;
42952 onNodeOut : function(n, dd, e, data){
42953 this.removeDropIndicators(n);
42956 onNodeDrop : function(n, dd, e, data){
42957 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
42960 var pt = this.getDropPoint(e, n, dd);
42961 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42962 if (pt == "below") { insertAt++; }
42963 for (var i = 0; i < data.records.length; i++) {
42964 var r = data.records[i];
42965 var dup = this.store.getById(r.id);
42966 if (dup && (dd != this.dragZone)) {
42967 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42970 this.store.insert(insertAt++, r.copy());
42972 data.source.isDirtyFlag = true;
42974 this.store.insert(insertAt++, r);
42976 this.isDirtyFlag = true;
42979 this.dragZone.cachedTarget = null;
42983 removeDropIndicators : function(n){
42985 Roo.fly(n).removeClass([
42986 "x-view-drag-insert-above",
42987 "x-view-drag-insert-below"]);
42988 this.lastInsertClass = "_noclass";
42993 * Utility method. Add a delete option to the DDView's context menu.
42994 * @param {String} imageUrl The URL of the "delete" icon image.
42996 setDeletable: function(imageUrl) {
42997 if (!this.singleSelect && !this.multiSelect) {
42998 this.singleSelect = true;
43000 var c = this.getContextMenu();
43001 this.contextMenu.on("itemclick", function(item) {
43004 this.remove(this.getSelectedIndexes());
43008 this.contextMenu.add({
43015 /** Return the context menu for this DDView. */
43016 getContextMenu: function() {
43017 if (!this.contextMenu) {
43018 // Create the View's context menu
43019 this.contextMenu = new Roo.menu.Menu({
43020 id: this.id + "-contextmenu"
43022 this.el.on("contextmenu", this.showContextMenu, this);
43024 return this.contextMenu;
43027 disableContextMenu: function() {
43028 if (this.contextMenu) {
43029 this.el.un("contextmenu", this.showContextMenu, this);
43033 showContextMenu: function(e, item) {
43034 item = this.findItemFromChild(e.getTarget());
43037 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
43038 this.contextMenu.showAt(e.getXY());
43043 * Remove {@link Roo.data.Record}s at the specified indices.
43044 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
43046 remove: function(selectedIndices) {
43047 selectedIndices = [].concat(selectedIndices);
43048 for (var i = 0; i < selectedIndices.length; i++) {
43049 var rec = this.store.getAt(selectedIndices[i]);
43050 this.store.remove(rec);
43055 * Double click fires the event, but also, if this is draggable, and there is only one other
43056 * related DropZone, it transfers the selected node.
43058 onDblClick : function(e){
43059 var item = this.findItemFromChild(e.getTarget());
43061 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43064 if (this.dragGroup) {
43065 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43066 while (targets.indexOf(this.dropZone) > -1) {
43067 targets.remove(this.dropZone);
43069 if (targets.length == 1) {
43070 this.dragZone.cachedTarget = null;
43071 var el = Roo.get(targets[0].getEl());
43072 var box = el.getBox(true);
43073 targets[0].onNodeDrop(el.dom, {
43075 xy: [box.x, box.y + box.height - 1]
43076 }, null, this.getDragData(e));
43082 handleSelection: function(e) {
43083 this.dragZone.cachedTarget = null;
43084 var item = this.findItemFromChild(e.getTarget());
43086 this.clearSelections(true);
43089 if (item && (this.multiSelect || this.singleSelect)){
43090 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43091 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43092 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43093 this.unselect(item);
43095 this.select(item, this.multiSelect && e.ctrlKey);
43096 this.lastSelection = item;
43101 onItemClick : function(item, index, e){
43102 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43108 unselect : function(nodeInfo, suppressEvent){
43109 var node = this.getNode(nodeInfo);
43110 if(node && this.isSelected(node)){
43111 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43112 Roo.fly(node).removeClass(this.selectedClass);
43113 this.selections.remove(node);
43114 if(!suppressEvent){
43115 this.fireEvent("selectionchange", this, this.selections);
43123 * Ext JS Library 1.1.1
43124 * Copyright(c) 2006-2007, Ext JS, LLC.
43126 * Originally Released Under LGPL - original licence link has changed is not relivant.
43129 * <script type="text/javascript">
43133 * @class Roo.LayoutManager
43134 * @extends Roo.util.Observable
43135 * Base class for layout managers.
43137 Roo.LayoutManager = function(container, config){
43138 Roo.LayoutManager.superclass.constructor.call(this);
43139 this.el = Roo.get(container);
43140 // ie scrollbar fix
43141 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43142 document.body.scroll = "no";
43143 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43144 this.el.position('relative');
43146 this.id = this.el.id;
43147 this.el.addClass("x-layout-container");
43148 /** false to disable window resize monitoring @type Boolean */
43149 this.monitorWindowResize = true;
43154 * Fires when a layout is performed.
43155 * @param {Roo.LayoutManager} this
43159 * @event regionresized
43160 * Fires when the user resizes a region.
43161 * @param {Roo.LayoutRegion} region The resized region
43162 * @param {Number} newSize The new size (width for east/west, height for north/south)
43164 "regionresized" : true,
43166 * @event regioncollapsed
43167 * Fires when a region is collapsed.
43168 * @param {Roo.LayoutRegion} region The collapsed region
43170 "regioncollapsed" : true,
43172 * @event regionexpanded
43173 * Fires when a region is expanded.
43174 * @param {Roo.LayoutRegion} region The expanded region
43176 "regionexpanded" : true
43178 this.updating = false;
43179 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43182 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43184 * Returns true if this layout is currently being updated
43185 * @return {Boolean}
43187 isUpdating : function(){
43188 return this.updating;
43192 * Suspend the LayoutManager from doing auto-layouts while
43193 * making multiple add or remove calls
43195 beginUpdate : function(){
43196 this.updating = true;
43200 * Restore auto-layouts and optionally disable the manager from performing a layout
43201 * @param {Boolean} noLayout true to disable a layout update
43203 endUpdate : function(noLayout){
43204 this.updating = false;
43210 layout: function(){
43214 onRegionResized : function(region, newSize){
43215 this.fireEvent("regionresized", region, newSize);
43219 onRegionCollapsed : function(region){
43220 this.fireEvent("regioncollapsed", region);
43223 onRegionExpanded : function(region){
43224 this.fireEvent("regionexpanded", region);
43228 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43229 * performs box-model adjustments.
43230 * @return {Object} The size as an object {width: (the width), height: (the height)}
43232 getViewSize : function(){
43234 if(this.el.dom != document.body){
43235 size = this.el.getSize();
43237 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43239 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43240 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43245 * Returns the Element this layout is bound to.
43246 * @return {Roo.Element}
43248 getEl : function(){
43253 * Returns the specified region.
43254 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43255 * @return {Roo.LayoutRegion}
43257 getRegion : function(target){
43258 return this.regions[target.toLowerCase()];
43261 onWindowResize : function(){
43262 if(this.monitorWindowResize){
43268 * Ext JS Library 1.1.1
43269 * Copyright(c) 2006-2007, Ext JS, LLC.
43271 * Originally Released Under LGPL - original licence link has changed is not relivant.
43274 * <script type="text/javascript">
43277 * @class Roo.BorderLayout
43278 * @extends Roo.LayoutManager
43279 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43280 * please see: <br><br>
43281 * <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>
43282 * <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>
43285 var layout = new Roo.BorderLayout(document.body, {
43319 preferredTabWidth: 150
43324 var CP = Roo.ContentPanel;
43326 layout.beginUpdate();
43327 layout.add("north", new CP("north", "North"));
43328 layout.add("south", new CP("south", {title: "South", closable: true}));
43329 layout.add("west", new CP("west", {title: "West"}));
43330 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43331 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43332 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43333 layout.getRegion("center").showPanel("center1");
43334 layout.endUpdate();
43337 <b>The container the layout is rendered into can be either the body element or any other element.
43338 If it is not the body element, the container needs to either be an absolute positioned element,
43339 or you will need to add "position:relative" to the css of the container. You will also need to specify
43340 the container size if it is not the body element.</b>
43343 * Create a new BorderLayout
43344 * @param {String/HTMLElement/Element} container The container this layout is bound to
43345 * @param {Object} config Configuration options
43347 Roo.BorderLayout = function(container, config){
43348 config = config || {};
43349 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43350 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43351 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43352 var target = this.factory.validRegions[i];
43353 if(config[target]){
43354 this.addRegion(target, config[target]);
43359 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43361 * Creates and adds a new region if it doesn't already exist.
43362 * @param {String} target The target region key (north, south, east, west or center).
43363 * @param {Object} config The regions config object
43364 * @return {BorderLayoutRegion} The new region
43366 addRegion : function(target, config){
43367 if(!this.regions[target]){
43368 var r = this.factory.create(target, this, config);
43369 this.bindRegion(target, r);
43371 return this.regions[target];
43375 bindRegion : function(name, r){
43376 this.regions[name] = r;
43377 r.on("visibilitychange", this.layout, this);
43378 r.on("paneladded", this.layout, this);
43379 r.on("panelremoved", this.layout, this);
43380 r.on("invalidated", this.layout, this);
43381 r.on("resized", this.onRegionResized, this);
43382 r.on("collapsed", this.onRegionCollapsed, this);
43383 r.on("expanded", this.onRegionExpanded, this);
43387 * Performs a layout update.
43389 layout : function(){
43390 if(this.updating) return;
43391 var size = this.getViewSize();
43392 var w = size.width;
43393 var h = size.height;
43398 //var x = 0, y = 0;
43400 var rs = this.regions;
43401 var north = rs["north"];
43402 var south = rs["south"];
43403 var west = rs["west"];
43404 var east = rs["east"];
43405 var center = rs["center"];
43406 //if(this.hideOnLayout){ // not supported anymore
43407 //c.el.setStyle("display", "none");
43409 if(north && north.isVisible()){
43410 var b = north.getBox();
43411 var m = north.getMargins();
43412 b.width = w - (m.left+m.right);
43415 centerY = b.height + b.y + m.bottom;
43416 centerH -= centerY;
43417 north.updateBox(this.safeBox(b));
43419 if(south && south.isVisible()){
43420 var b = south.getBox();
43421 var m = south.getMargins();
43422 b.width = w - (m.left+m.right);
43424 var totalHeight = (b.height + m.top + m.bottom);
43425 b.y = h - totalHeight + m.top;
43426 centerH -= totalHeight;
43427 south.updateBox(this.safeBox(b));
43429 if(west && west.isVisible()){
43430 var b = west.getBox();
43431 var m = west.getMargins();
43432 b.height = centerH - (m.top+m.bottom);
43434 b.y = centerY + m.top;
43435 var totalWidth = (b.width + m.left + m.right);
43436 centerX += totalWidth;
43437 centerW -= totalWidth;
43438 west.updateBox(this.safeBox(b));
43440 if(east && east.isVisible()){
43441 var b = east.getBox();
43442 var m = east.getMargins();
43443 b.height = centerH - (m.top+m.bottom);
43444 var totalWidth = (b.width + m.left + m.right);
43445 b.x = w - totalWidth + m.left;
43446 b.y = centerY + m.top;
43447 centerW -= totalWidth;
43448 east.updateBox(this.safeBox(b));
43451 var m = center.getMargins();
43453 x: centerX + m.left,
43454 y: centerY + m.top,
43455 width: centerW - (m.left+m.right),
43456 height: centerH - (m.top+m.bottom)
43458 //if(this.hideOnLayout){
43459 //center.el.setStyle("display", "block");
43461 center.updateBox(this.safeBox(centerBox));
43464 this.fireEvent("layout", this);
43468 safeBox : function(box){
43469 box.width = Math.max(0, box.width);
43470 box.height = Math.max(0, box.height);
43475 * Adds a ContentPanel (or subclass) to this layout.
43476 * @param {String} target The target region key (north, south, east, west or center).
43477 * @param {Roo.ContentPanel} panel The panel to add
43478 * @return {Roo.ContentPanel} The added panel
43480 add : function(target, panel){
43482 target = target.toLowerCase();
43483 return this.regions[target].add(panel);
43487 * Remove a ContentPanel (or subclass) to this layout.
43488 * @param {String} target The target region key (north, south, east, west or center).
43489 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43490 * @return {Roo.ContentPanel} The removed panel
43492 remove : function(target, panel){
43493 target = target.toLowerCase();
43494 return this.regions[target].remove(panel);
43498 * Searches all regions for a panel with the specified id
43499 * @param {String} panelId
43500 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43502 findPanel : function(panelId){
43503 var rs = this.regions;
43504 for(var target in rs){
43505 if(typeof rs[target] != "function"){
43506 var p = rs[target].getPanel(panelId);
43516 * Searches all regions for a panel with the specified id and activates (shows) it.
43517 * @param {String/ContentPanel} panelId The panels id or the panel itself
43518 * @return {Roo.ContentPanel} The shown panel or null
43520 showPanel : function(panelId) {
43521 var rs = this.regions;
43522 for(var target in rs){
43523 var r = rs[target];
43524 if(typeof r != "function"){
43525 if(r.hasPanel(panelId)){
43526 return r.showPanel(panelId);
43534 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43535 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43537 restoreState : function(provider){
43539 provider = Roo.state.Manager;
43541 var sm = new Roo.LayoutStateManager();
43542 sm.init(this, provider);
43546 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43547 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43548 * a valid ContentPanel config object. Example:
43550 // Create the main layout
43551 var layout = new Roo.BorderLayout('main-ct', {
43562 // Create and add multiple ContentPanels at once via configs
43565 id: 'source-files',
43567 title:'Ext Source Files',
43580 * @param {Object} regions An object containing ContentPanel configs by region name
43582 batchAdd : function(regions){
43583 this.beginUpdate();
43584 for(var rname in regions){
43585 var lr = this.regions[rname];
43587 this.addTypedPanels(lr, regions[rname]);
43594 addTypedPanels : function(lr, ps){
43595 if(typeof ps == 'string'){
43596 lr.add(new Roo.ContentPanel(ps));
43598 else if(ps instanceof Array){
43599 for(var i =0, len = ps.length; i < len; i++){
43600 this.addTypedPanels(lr, ps[i]);
43603 else if(!ps.events){ // raw config?
43605 delete ps.el; // prevent conflict
43606 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43608 else { // panel object assumed!
43613 * Adds a xtype elements to the layout.
43617 xtype : 'ContentPanel',
43624 xtype : 'NestedLayoutPanel',
43630 items : [ ... list of content panels or nested layout panels.. ]
43634 * @param {Object} cfg Xtype definition of item to add.
43636 addxtype : function(cfg)
43638 // basically accepts a pannel...
43639 // can accept a layout region..!?!?
43640 // console.log('BorderLayout add ' + cfg.xtype)
43642 if (!cfg.xtype.match(/Panel$/)) {
43646 var region = cfg.region;
43652 xitems = cfg.items;
43659 case 'ContentPanel': // ContentPanel (el, cfg)
43660 case 'ScrollPanel': // ContentPanel (el, cfg)
43661 if(cfg.autoCreate) {
43662 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43664 var el = this.el.createChild();
43665 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43668 this.add(region, ret);
43672 case 'TreePanel': // our new panel!
43673 cfg.el = this.el.createChild();
43674 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43675 this.add(region, ret);
43678 case 'NestedLayoutPanel':
43679 // create a new Layout (which is a Border Layout...
43680 var el = this.el.createChild();
43681 var clayout = cfg.layout;
43683 clayout.items = clayout.items || [];
43684 // replace this exitems with the clayout ones..
43685 xitems = clayout.items;
43688 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43689 cfg.background = false;
43691 var layout = new Roo.BorderLayout(el, clayout);
43693 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43694 //console.log('adding nested layout panel ' + cfg.toSource());
43695 this.add(region, ret);
43701 // needs grid and region
43703 //var el = this.getRegion(region).el.createChild();
43704 var el = this.el.createChild();
43705 // create the grid first...
43707 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43709 if (region == 'center' && this.active ) {
43710 cfg.background = false;
43712 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43714 this.add(region, ret);
43715 if (cfg.background) {
43716 ret.on('activate', function(gp) {
43717 if (!gp.grid.rendered) {
43730 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43732 // GridPanel (grid, cfg)
43735 this.beginUpdate();
43737 Roo.each(xitems, function(i) {
43747 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43748 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43749 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43750 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43753 var CP = Roo.ContentPanel;
43755 var layout = Roo.BorderLayout.create({
43759 panels: [new CP("north", "North")]
43768 panels: [new CP("west", {title: "West"})]
43777 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43786 panels: [new CP("south", {title: "South", closable: true})]
43793 preferredTabWidth: 150,
43795 new CP("center1", {title: "Close Me", closable: true}),
43796 new CP("center2", {title: "Center Panel", closable: false})
43801 layout.getRegion("center").showPanel("center1");
43806 Roo.BorderLayout.create = function(config, targetEl){
43807 var layout = new Roo.BorderLayout(targetEl || document.body, config);
43808 layout.beginUpdate();
43809 var regions = Roo.BorderLayout.RegionFactory.validRegions;
43810 for(var j = 0, jlen = regions.length; j < jlen; j++){
43811 var lr = regions[j];
43812 if(layout.regions[lr] && config[lr].panels){
43813 var r = layout.regions[lr];
43814 var ps = config[lr].panels;
43815 layout.addTypedPanels(r, ps);
43818 layout.endUpdate();
43823 Roo.BorderLayout.RegionFactory = {
43825 validRegions : ["north","south","east","west","center"],
43828 create : function(target, mgr, config){
43829 target = target.toLowerCase();
43830 if(config.lightweight || config.basic){
43831 return new Roo.BasicLayoutRegion(mgr, config, target);
43835 return new Roo.NorthLayoutRegion(mgr, config);
43837 return new Roo.SouthLayoutRegion(mgr, config);
43839 return new Roo.EastLayoutRegion(mgr, config);
43841 return new Roo.WestLayoutRegion(mgr, config);
43843 return new Roo.CenterLayoutRegion(mgr, config);
43845 throw 'Layout region "'+target+'" not supported.';
43849 * Ext JS Library 1.1.1
43850 * Copyright(c) 2006-2007, Ext JS, LLC.
43852 * Originally Released Under LGPL - original licence link has changed is not relivant.
43855 * <script type="text/javascript">
43859 * @class Roo.BasicLayoutRegion
43860 * @extends Roo.util.Observable
43861 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43862 * and does not have a titlebar, tabs or any other features. All it does is size and position
43863 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43865 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
43867 this.position = pos;
43870 * @scope Roo.BasicLayoutRegion
43874 * @event beforeremove
43875 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43876 * @param {Roo.LayoutRegion} this
43877 * @param {Roo.ContentPanel} panel The panel
43878 * @param {Object} e The cancel event object
43880 "beforeremove" : true,
43882 * @event invalidated
43883 * Fires when the layout for this region is changed.
43884 * @param {Roo.LayoutRegion} this
43886 "invalidated" : true,
43888 * @event visibilitychange
43889 * Fires when this region is shown or hidden
43890 * @param {Roo.LayoutRegion} this
43891 * @param {Boolean} visibility true or false
43893 "visibilitychange" : true,
43895 * @event paneladded
43896 * Fires when a panel is added.
43897 * @param {Roo.LayoutRegion} this
43898 * @param {Roo.ContentPanel} panel The panel
43900 "paneladded" : true,
43902 * @event panelremoved
43903 * Fires when a panel is removed.
43904 * @param {Roo.LayoutRegion} this
43905 * @param {Roo.ContentPanel} panel The panel
43907 "panelremoved" : true,
43910 * Fires when this region is collapsed.
43911 * @param {Roo.LayoutRegion} this
43913 "collapsed" : true,
43916 * Fires when this region is expanded.
43917 * @param {Roo.LayoutRegion} this
43922 * Fires when this region is slid into view.
43923 * @param {Roo.LayoutRegion} this
43925 "slideshow" : true,
43928 * Fires when this region slides out of view.
43929 * @param {Roo.LayoutRegion} this
43931 "slidehide" : true,
43933 * @event panelactivated
43934 * Fires when a panel is activated.
43935 * @param {Roo.LayoutRegion} this
43936 * @param {Roo.ContentPanel} panel The activated panel
43938 "panelactivated" : true,
43941 * Fires when the user resizes this region.
43942 * @param {Roo.LayoutRegion} this
43943 * @param {Number} newSize The new size (width for east/west, height for north/south)
43947 /** A collection of panels in this region. @type Roo.util.MixedCollection */
43948 this.panels = new Roo.util.MixedCollection();
43949 this.panels.getKey = this.getPanelId.createDelegate(this);
43951 this.activePanel = null;
43952 // ensure listeners are added...
43954 if (config.listeners || config.events) {
43955 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43956 listeners : config.listeners || {},
43957 events : config.events || {}
43961 if(skipConfig !== true){
43962 this.applyConfig(config);
43966 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43967 getPanelId : function(p){
43971 applyConfig : function(config){
43972 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43973 this.config = config;
43978 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
43979 * the width, for horizontal (north, south) the height.
43980 * @param {Number} newSize The new width or height
43982 resizeTo : function(newSize){
43983 var el = this.el ? this.el :
43984 (this.activePanel ? this.activePanel.getEl() : null);
43986 switch(this.position){
43989 el.setWidth(newSize);
43990 this.fireEvent("resized", this, newSize);
43994 el.setHeight(newSize);
43995 this.fireEvent("resized", this, newSize);
44001 getBox : function(){
44002 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
44005 getMargins : function(){
44006 return this.margins;
44009 updateBox : function(box){
44011 var el = this.activePanel.getEl();
44012 el.dom.style.left = box.x + "px";
44013 el.dom.style.top = box.y + "px";
44014 this.activePanel.setSize(box.width, box.height);
44018 * Returns the container element for this region.
44019 * @return {Roo.Element}
44021 getEl : function(){
44022 return this.activePanel;
44026 * Returns true if this region is currently visible.
44027 * @return {Boolean}
44029 isVisible : function(){
44030 return this.activePanel ? true : false;
44033 setActivePanel : function(panel){
44034 panel = this.getPanel(panel);
44035 if(this.activePanel && this.activePanel != panel){
44036 this.activePanel.setActiveState(false);
44037 this.activePanel.getEl().setLeftTop(-10000,-10000);
44039 this.activePanel = panel;
44040 panel.setActiveState(true);
44042 panel.setSize(this.box.width, this.box.height);
44044 this.fireEvent("panelactivated", this, panel);
44045 this.fireEvent("invalidated");
44049 * Show the specified panel.
44050 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
44051 * @return {Roo.ContentPanel} The shown panel or null
44053 showPanel : function(panel){
44054 if(panel = this.getPanel(panel)){
44055 this.setActivePanel(panel);
44061 * Get the active panel for this region.
44062 * @return {Roo.ContentPanel} The active panel or null
44064 getActivePanel : function(){
44065 return this.activePanel;
44069 * Add the passed ContentPanel(s)
44070 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44071 * @return {Roo.ContentPanel} The panel added (if only one was added)
44073 add : function(panel){
44074 if(arguments.length > 1){
44075 for(var i = 0, len = arguments.length; i < len; i++) {
44076 this.add(arguments[i]);
44080 if(this.hasPanel(panel)){
44081 this.showPanel(panel);
44084 var el = panel.getEl();
44085 if(el.dom.parentNode != this.mgr.el.dom){
44086 this.mgr.el.dom.appendChild(el.dom);
44088 if(panel.setRegion){
44089 panel.setRegion(this);
44091 this.panels.add(panel);
44092 el.setStyle("position", "absolute");
44093 if(!panel.background){
44094 this.setActivePanel(panel);
44095 if(this.config.initialSize && this.panels.getCount()==1){
44096 this.resizeTo(this.config.initialSize);
44099 this.fireEvent("paneladded", this, panel);
44104 * Returns true if the panel is in this region.
44105 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44106 * @return {Boolean}
44108 hasPanel : function(panel){
44109 if(typeof panel == "object"){ // must be panel obj
44110 panel = panel.getId();
44112 return this.getPanel(panel) ? true : false;
44116 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44117 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44118 * @param {Boolean} preservePanel Overrides the config preservePanel option
44119 * @return {Roo.ContentPanel} The panel that was removed
44121 remove : function(panel, preservePanel){
44122 panel = this.getPanel(panel);
44127 this.fireEvent("beforeremove", this, panel, e);
44128 if(e.cancel === true){
44131 var panelId = panel.getId();
44132 this.panels.removeKey(panelId);
44137 * Returns the panel specified or null if it's not in this region.
44138 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44139 * @return {Roo.ContentPanel}
44141 getPanel : function(id){
44142 if(typeof id == "object"){ // must be panel obj
44145 return this.panels.get(id);
44149 * Returns this regions position (north/south/east/west/center).
44152 getPosition: function(){
44153 return this.position;
44157 * Ext JS Library 1.1.1
44158 * Copyright(c) 2006-2007, Ext JS, LLC.
44160 * Originally Released Under LGPL - original licence link has changed is not relivant.
44163 * <script type="text/javascript">
44167 * @class Roo.LayoutRegion
44168 * @extends Roo.BasicLayoutRegion
44169 * This class represents a region in a layout manager.
44170 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44171 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44172 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44173 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44174 * @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})
44175 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44176 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44177 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44178 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44179 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44180 * @cfg {String} title The title for the region (overrides panel titles)
44181 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44182 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44183 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44184 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44185 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44186 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44187 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44188 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44189 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44190 * @cfg {Boolean} showPin True to show a pin button
44191 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44192 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44193 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44194 * @cfg {Number} width For East/West panels
44195 * @cfg {Number} height For North/South panels
44196 * @cfg {Boolean} split To show the splitter
44198 Roo.LayoutRegion = function(mgr, config, pos){
44199 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44200 var dh = Roo.DomHelper;
44201 /** This region's container element
44202 * @type Roo.Element */
44203 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44204 /** This region's title element
44205 * @type Roo.Element */
44207 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44208 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44209 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44211 this.titleEl.enableDisplayMode();
44212 /** This region's title text element
44213 * @type HTMLElement */
44214 this.titleTextEl = this.titleEl.dom.firstChild;
44215 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44216 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44217 this.closeBtn.enableDisplayMode();
44218 this.closeBtn.on("click", this.closeClicked, this);
44219 this.closeBtn.hide();
44221 this.createBody(config);
44222 this.visible = true;
44223 this.collapsed = false;
44225 if(config.hideWhenEmpty){
44227 this.on("paneladded", this.validateVisibility, this);
44228 this.on("panelremoved", this.validateVisibility, this);
44230 this.applyConfig(config);
44233 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44235 createBody : function(){
44236 /** This region's body element
44237 * @type Roo.Element */
44238 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44241 applyConfig : function(c){
44242 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44243 var dh = Roo.DomHelper;
44244 if(c.titlebar !== false){
44245 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44246 this.collapseBtn.on("click", this.collapse, this);
44247 this.collapseBtn.enableDisplayMode();
44249 if(c.showPin === true || this.showPin){
44250 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44251 this.stickBtn.enableDisplayMode();
44252 this.stickBtn.on("click", this.expand, this);
44253 this.stickBtn.hide();
44256 /** This region's collapsed element
44257 * @type Roo.Element */
44258 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44259 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44261 if(c.floatable !== false){
44262 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44263 this.collapsedEl.on("click", this.collapseClick, this);
44266 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44267 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44268 id: "message", unselectable: "on", style:{"float":"left"}});
44269 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44271 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44272 this.expandBtn.on("click", this.expand, this);
44274 if(this.collapseBtn){
44275 this.collapseBtn.setVisible(c.collapsible == true);
44277 this.cmargins = c.cmargins || this.cmargins ||
44278 (this.position == "west" || this.position == "east" ?
44279 {top: 0, left: 2, right:2, bottom: 0} :
44280 {top: 2, left: 0, right:0, bottom: 2});
44281 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44282 this.bottomTabs = c.tabPosition != "top";
44283 this.autoScroll = c.autoScroll || false;
44284 if(this.autoScroll){
44285 this.bodyEl.setStyle("overflow", "auto");
44287 this.bodyEl.setStyle("overflow", "hidden");
44289 //if(c.titlebar !== false){
44290 if((!c.titlebar && !c.title) || c.titlebar === false){
44291 this.titleEl.hide();
44293 this.titleEl.show();
44295 this.titleTextEl.innerHTML = c.title;
44299 this.duration = c.duration || .30;
44300 this.slideDuration = c.slideDuration || .45;
44303 this.collapse(true);
44310 * Returns true if this region is currently visible.
44311 * @return {Boolean}
44313 isVisible : function(){
44314 return this.visible;
44318 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44319 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44321 setCollapsedTitle : function(title){
44322 title = title || " ";
44323 if(this.collapsedTitleTextEl){
44324 this.collapsedTitleTextEl.innerHTML = title;
44328 getBox : function(){
44330 if(!this.collapsed){
44331 b = this.el.getBox(false, true);
44333 b = this.collapsedEl.getBox(false, true);
44338 getMargins : function(){
44339 return this.collapsed ? this.cmargins : this.margins;
44342 highlight : function(){
44343 this.el.addClass("x-layout-panel-dragover");
44346 unhighlight : function(){
44347 this.el.removeClass("x-layout-panel-dragover");
44350 updateBox : function(box){
44352 if(!this.collapsed){
44353 this.el.dom.style.left = box.x + "px";
44354 this.el.dom.style.top = box.y + "px";
44355 this.updateBody(box.width, box.height);
44357 this.collapsedEl.dom.style.left = box.x + "px";
44358 this.collapsedEl.dom.style.top = box.y + "px";
44359 this.collapsedEl.setSize(box.width, box.height);
44362 this.tabs.autoSizeTabs();
44366 updateBody : function(w, h){
44368 this.el.setWidth(w);
44369 w -= this.el.getBorderWidth("rl");
44370 if(this.config.adjustments){
44371 w += this.config.adjustments[0];
44375 this.el.setHeight(h);
44376 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44377 h -= this.el.getBorderWidth("tb");
44378 if(this.config.adjustments){
44379 h += this.config.adjustments[1];
44381 this.bodyEl.setHeight(h);
44383 h = this.tabs.syncHeight(h);
44386 if(this.panelSize){
44387 w = w !== null ? w : this.panelSize.width;
44388 h = h !== null ? h : this.panelSize.height;
44390 if(this.activePanel){
44391 var el = this.activePanel.getEl();
44392 w = w !== null ? w : el.getWidth();
44393 h = h !== null ? h : el.getHeight();
44394 this.panelSize = {width: w, height: h};
44395 this.activePanel.setSize(w, h);
44397 if(Roo.isIE && this.tabs){
44398 this.tabs.el.repaint();
44403 * Returns the container element for this region.
44404 * @return {Roo.Element}
44406 getEl : function(){
44411 * Hides this region.
44414 if(!this.collapsed){
44415 this.el.dom.style.left = "-2000px";
44418 this.collapsedEl.dom.style.left = "-2000px";
44419 this.collapsedEl.hide();
44421 this.visible = false;
44422 this.fireEvent("visibilitychange", this, false);
44426 * Shows this region if it was previously hidden.
44429 if(!this.collapsed){
44432 this.collapsedEl.show();
44434 this.visible = true;
44435 this.fireEvent("visibilitychange", this, true);
44438 closeClicked : function(){
44439 if(this.activePanel){
44440 this.remove(this.activePanel);
44444 collapseClick : function(e){
44446 e.stopPropagation();
44449 e.stopPropagation();
44455 * Collapses this region.
44456 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44458 collapse : function(skipAnim){
44459 if(this.collapsed) return;
44460 this.collapsed = true;
44462 this.split.el.hide();
44464 if(this.config.animate && skipAnim !== true){
44465 this.fireEvent("invalidated", this);
44466 this.animateCollapse();
44468 this.el.setLocation(-20000,-20000);
44470 this.collapsedEl.show();
44471 this.fireEvent("collapsed", this);
44472 this.fireEvent("invalidated", this);
44476 animateCollapse : function(){
44481 * Expands this region if it was previously collapsed.
44482 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44483 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44485 expand : function(e, skipAnim){
44486 if(e) e.stopPropagation();
44487 if(!this.collapsed || this.el.hasActiveFx()) return;
44489 this.afterSlideIn();
44492 this.collapsed = false;
44493 if(this.config.animate && skipAnim !== true){
44494 this.animateExpand();
44498 this.split.el.show();
44500 this.collapsedEl.setLocation(-2000,-2000);
44501 this.collapsedEl.hide();
44502 this.fireEvent("invalidated", this);
44503 this.fireEvent("expanded", this);
44507 animateExpand : function(){
44511 initTabs : function(){
44512 this.bodyEl.setStyle("overflow", "hidden");
44513 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44514 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44515 disableTooltips: this.config.disableTabTips
44517 if(this.config.hideTabs){
44518 ts.stripWrap.setDisplayed(false);
44521 ts.resizeTabs = this.config.resizeTabs === true;
44522 ts.minTabWidth = this.config.minTabWidth || 40;
44523 ts.maxTabWidth = this.config.maxTabWidth || 250;
44524 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44525 ts.monitorResize = false;
44526 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44527 ts.bodyEl.addClass('x-layout-tabs-body');
44528 this.panels.each(this.initPanelAsTab, this);
44531 initPanelAsTab : function(panel){
44532 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44533 this.config.closeOnTab && panel.isClosable());
44534 if(panel.tabTip !== undefined){
44535 ti.setTooltip(panel.tabTip);
44537 ti.on("activate", function(){
44538 this.setActivePanel(panel);
44540 if(this.config.closeOnTab){
44541 ti.on("beforeclose", function(t, e){
44543 this.remove(panel);
44549 updatePanelTitle : function(panel, title){
44550 if(this.activePanel == panel){
44551 this.updateTitle(title);
44554 var ti = this.tabs.getTab(panel.getEl().id);
44556 if(panel.tabTip !== undefined){
44557 ti.setTooltip(panel.tabTip);
44562 updateTitle : function(title){
44563 if(this.titleTextEl && !this.config.title){
44564 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44568 setActivePanel : function(panel){
44569 panel = this.getPanel(panel);
44570 if(this.activePanel && this.activePanel != panel){
44571 this.activePanel.setActiveState(false);
44573 this.activePanel = panel;
44574 panel.setActiveState(true);
44575 if(this.panelSize){
44576 panel.setSize(this.panelSize.width, this.panelSize.height);
44579 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44581 this.updateTitle(panel.getTitle());
44583 this.fireEvent("invalidated", this);
44585 this.fireEvent("panelactivated", this, panel);
44589 * Shows the specified panel.
44590 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44591 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44593 showPanel : function(panel){
44594 if(panel = this.getPanel(panel)){
44596 var tab = this.tabs.getTab(panel.getEl().id);
44597 if(tab.isHidden()){
44598 this.tabs.unhideTab(tab.id);
44602 this.setActivePanel(panel);
44609 * Get the active panel for this region.
44610 * @return {Roo.ContentPanel} The active panel or null
44612 getActivePanel : function(){
44613 return this.activePanel;
44616 validateVisibility : function(){
44617 if(this.panels.getCount() < 1){
44618 this.updateTitle(" ");
44619 this.closeBtn.hide();
44622 if(!this.isVisible()){
44629 * Adds the passed ContentPanel(s) to this region.
44630 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44631 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44633 add : function(panel){
44634 if(arguments.length > 1){
44635 for(var i = 0, len = arguments.length; i < len; i++) {
44636 this.add(arguments[i]);
44640 if(this.hasPanel(panel)){
44641 this.showPanel(panel);
44644 panel.setRegion(this);
44645 this.panels.add(panel);
44646 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44647 this.bodyEl.dom.appendChild(panel.getEl().dom);
44648 if(panel.background !== true){
44649 this.setActivePanel(panel);
44651 this.fireEvent("paneladded", this, panel);
44657 this.initPanelAsTab(panel);
44659 if(panel.background !== true){
44660 this.tabs.activate(panel.getEl().id);
44662 this.fireEvent("paneladded", this, panel);
44667 * Hides the tab for the specified panel.
44668 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44670 hidePanel : function(panel){
44671 if(this.tabs && (panel = this.getPanel(panel))){
44672 this.tabs.hideTab(panel.getEl().id);
44677 * Unhides the tab for a previously hidden panel.
44678 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44680 unhidePanel : function(panel){
44681 if(this.tabs && (panel = this.getPanel(panel))){
44682 this.tabs.unhideTab(panel.getEl().id);
44686 clearPanels : function(){
44687 while(this.panels.getCount() > 0){
44688 this.remove(this.panels.first());
44693 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44694 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44695 * @param {Boolean} preservePanel Overrides the config preservePanel option
44696 * @return {Roo.ContentPanel} The panel that was removed
44698 remove : function(panel, preservePanel){
44699 panel = this.getPanel(panel);
44704 this.fireEvent("beforeremove", this, panel, e);
44705 if(e.cancel === true){
44708 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44709 var panelId = panel.getId();
44710 this.panels.removeKey(panelId);
44712 document.body.appendChild(panel.getEl().dom);
44715 this.tabs.removeTab(panel.getEl().id);
44716 }else if (!preservePanel){
44717 this.bodyEl.dom.removeChild(panel.getEl().dom);
44719 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44720 var p = this.panels.first();
44721 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44722 tempEl.appendChild(p.getEl().dom);
44723 this.bodyEl.update("");
44724 this.bodyEl.dom.appendChild(p.getEl().dom);
44726 this.updateTitle(p.getTitle());
44728 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44729 this.setActivePanel(p);
44731 panel.setRegion(null);
44732 if(this.activePanel == panel){
44733 this.activePanel = null;
44735 if(this.config.autoDestroy !== false && preservePanel !== true){
44736 try{panel.destroy();}catch(e){}
44738 this.fireEvent("panelremoved", this, panel);
44743 * Returns the TabPanel component used by this region
44744 * @return {Roo.TabPanel}
44746 getTabs : function(){
44750 createTool : function(parentEl, className){
44751 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44752 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44753 btn.addClassOnOver("x-layout-tools-button-over");
44758 * Ext JS Library 1.1.1
44759 * Copyright(c) 2006-2007, Ext JS, LLC.
44761 * Originally Released Under LGPL - original licence link has changed is not relivant.
44764 * <script type="text/javascript">
44770 * @class Roo.SplitLayoutRegion
44771 * @extends Roo.LayoutRegion
44772 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44774 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44775 this.cursor = cursor;
44776 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44779 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44780 splitTip : "Drag to resize.",
44781 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44782 useSplitTips : false,
44784 applyConfig : function(config){
44785 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44788 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44789 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44790 /** The SplitBar for this region
44791 * @type Roo.SplitBar */
44792 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44793 this.split.on("moved", this.onSplitMove, this);
44794 this.split.useShim = config.useShim === true;
44795 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44796 if(this.useSplitTips){
44797 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44799 if(config.collapsible){
44800 this.split.el.on("dblclick", this.collapse, this);
44803 if(typeof config.minSize != "undefined"){
44804 this.split.minSize = config.minSize;
44806 if(typeof config.maxSize != "undefined"){
44807 this.split.maxSize = config.maxSize;
44809 if(config.hideWhenEmpty || config.hidden || config.collapsed){
44810 this.hideSplitter();
44815 getHMaxSize : function(){
44816 var cmax = this.config.maxSize || 10000;
44817 var center = this.mgr.getRegion("center");
44818 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
44821 getVMaxSize : function(){
44822 var cmax = this.config.maxSize || 10000;
44823 var center = this.mgr.getRegion("center");
44824 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
44827 onSplitMove : function(split, newSize){
44828 this.fireEvent("resized", this, newSize);
44832 * Returns the {@link Roo.SplitBar} for this region.
44833 * @return {Roo.SplitBar}
44835 getSplitBar : function(){
44840 this.hideSplitter();
44841 Roo.SplitLayoutRegion.superclass.hide.call(this);
44844 hideSplitter : function(){
44846 this.split.el.setLocation(-2000,-2000);
44847 this.split.el.hide();
44853 this.split.el.show();
44855 Roo.SplitLayoutRegion.superclass.show.call(this);
44858 beforeSlide: function(){
44859 if(Roo.isGecko){// firefox overflow auto bug workaround
44860 this.bodyEl.clip();
44861 if(this.tabs) this.tabs.bodyEl.clip();
44862 if(this.activePanel){
44863 this.activePanel.getEl().clip();
44865 if(this.activePanel.beforeSlide){
44866 this.activePanel.beforeSlide();
44872 afterSlide : function(){
44873 if(Roo.isGecko){// firefox overflow auto bug workaround
44874 this.bodyEl.unclip();
44875 if(this.tabs) this.tabs.bodyEl.unclip();
44876 if(this.activePanel){
44877 this.activePanel.getEl().unclip();
44878 if(this.activePanel.afterSlide){
44879 this.activePanel.afterSlide();
44885 initAutoHide : function(){
44886 if(this.autoHide !== false){
44887 if(!this.autoHideHd){
44888 var st = new Roo.util.DelayedTask(this.slideIn, this);
44889 this.autoHideHd = {
44890 "mouseout": function(e){
44891 if(!e.within(this.el, true)){
44895 "mouseover" : function(e){
44901 this.el.on(this.autoHideHd);
44905 clearAutoHide : function(){
44906 if(this.autoHide !== false){
44907 this.el.un("mouseout", this.autoHideHd.mouseout);
44908 this.el.un("mouseover", this.autoHideHd.mouseover);
44912 clearMonitor : function(){
44913 Roo.get(document).un("click", this.slideInIf, this);
44916 // these names are backwards but not changed for compat
44917 slideOut : function(){
44918 if(this.isSlid || this.el.hasActiveFx()){
44921 this.isSlid = true;
44922 if(this.collapseBtn){
44923 this.collapseBtn.hide();
44925 this.closeBtnState = this.closeBtn.getStyle('display');
44926 this.closeBtn.hide();
44928 this.stickBtn.show();
44931 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44932 this.beforeSlide();
44933 this.el.setStyle("z-index", 10001);
44934 this.el.slideIn(this.getSlideAnchor(), {
44935 callback: function(){
44937 this.initAutoHide();
44938 Roo.get(document).on("click", this.slideInIf, this);
44939 this.fireEvent("slideshow", this);
44946 afterSlideIn : function(){
44947 this.clearAutoHide();
44948 this.isSlid = false;
44949 this.clearMonitor();
44950 this.el.setStyle("z-index", "");
44951 if(this.collapseBtn){
44952 this.collapseBtn.show();
44954 this.closeBtn.setStyle('display', this.closeBtnState);
44956 this.stickBtn.hide();
44958 this.fireEvent("slidehide", this);
44961 slideIn : function(cb){
44962 if(!this.isSlid || this.el.hasActiveFx()){
44966 this.isSlid = false;
44967 this.beforeSlide();
44968 this.el.slideOut(this.getSlideAnchor(), {
44969 callback: function(){
44970 this.el.setLeftTop(-10000, -10000);
44972 this.afterSlideIn();
44980 slideInIf : function(e){
44981 if(!e.within(this.el)){
44986 animateCollapse : function(){
44987 this.beforeSlide();
44988 this.el.setStyle("z-index", 20000);
44989 var anchor = this.getSlideAnchor();
44990 this.el.slideOut(anchor, {
44991 callback : function(){
44992 this.el.setStyle("z-index", "");
44993 this.collapsedEl.slideIn(anchor, {duration:.3});
44995 this.el.setLocation(-10000,-10000);
44997 this.fireEvent("collapsed", this);
45004 animateExpand : function(){
45005 this.beforeSlide();
45006 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
45007 this.el.setStyle("z-index", 20000);
45008 this.collapsedEl.hide({
45011 this.el.slideIn(this.getSlideAnchor(), {
45012 callback : function(){
45013 this.el.setStyle("z-index", "");
45016 this.split.el.show();
45018 this.fireEvent("invalidated", this);
45019 this.fireEvent("expanded", this);
45047 getAnchor : function(){
45048 return this.anchors[this.position];
45051 getCollapseAnchor : function(){
45052 return this.canchors[this.position];
45055 getSlideAnchor : function(){
45056 return this.sanchors[this.position];
45059 getAlignAdj : function(){
45060 var cm = this.cmargins;
45061 switch(this.position){
45077 getExpandAdj : function(){
45078 var c = this.collapsedEl, cm = this.cmargins;
45079 switch(this.position){
45081 return [-(cm.right+c.getWidth()+cm.left), 0];
45084 return [cm.right+c.getWidth()+cm.left, 0];
45087 return [0, -(cm.top+cm.bottom+c.getHeight())];
45090 return [0, cm.top+cm.bottom+c.getHeight()];
45096 * Ext JS Library 1.1.1
45097 * Copyright(c) 2006-2007, Ext JS, LLC.
45099 * Originally Released Under LGPL - original licence link has changed is not relivant.
45102 * <script type="text/javascript">
45105 * These classes are private internal classes
45107 Roo.CenterLayoutRegion = function(mgr, config){
45108 Roo.LayoutRegion.call(this, mgr, config, "center");
45109 this.visible = true;
45110 this.minWidth = config.minWidth || 20;
45111 this.minHeight = config.minHeight || 20;
45114 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45116 // center panel can't be hidden
45120 // center panel can't be hidden
45123 getMinWidth: function(){
45124 return this.minWidth;
45127 getMinHeight: function(){
45128 return this.minHeight;
45133 Roo.NorthLayoutRegion = function(mgr, config){
45134 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45136 this.split.placement = Roo.SplitBar.TOP;
45137 this.split.orientation = Roo.SplitBar.VERTICAL;
45138 this.split.el.addClass("x-layout-split-v");
45140 var size = config.initialSize || config.height;
45141 if(typeof size != "undefined"){
45142 this.el.setHeight(size);
45145 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45146 orientation: Roo.SplitBar.VERTICAL,
45147 getBox : function(){
45148 if(this.collapsed){
45149 return this.collapsedEl.getBox();
45151 var box = this.el.getBox();
45153 box.height += this.split.el.getHeight();
45158 updateBox : function(box){
45159 if(this.split && !this.collapsed){
45160 box.height -= this.split.el.getHeight();
45161 this.split.el.setLeft(box.x);
45162 this.split.el.setTop(box.y+box.height);
45163 this.split.el.setWidth(box.width);
45165 if(this.collapsed){
45166 this.updateBody(box.width, null);
45168 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45172 Roo.SouthLayoutRegion = function(mgr, config){
45173 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45175 this.split.placement = Roo.SplitBar.BOTTOM;
45176 this.split.orientation = Roo.SplitBar.VERTICAL;
45177 this.split.el.addClass("x-layout-split-v");
45179 var size = config.initialSize || config.height;
45180 if(typeof size != "undefined"){
45181 this.el.setHeight(size);
45184 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45185 orientation: Roo.SplitBar.VERTICAL,
45186 getBox : function(){
45187 if(this.collapsed){
45188 return this.collapsedEl.getBox();
45190 var box = this.el.getBox();
45192 var sh = this.split.el.getHeight();
45199 updateBox : function(box){
45200 if(this.split && !this.collapsed){
45201 var sh = this.split.el.getHeight();
45204 this.split.el.setLeft(box.x);
45205 this.split.el.setTop(box.y-sh);
45206 this.split.el.setWidth(box.width);
45208 if(this.collapsed){
45209 this.updateBody(box.width, null);
45211 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45215 Roo.EastLayoutRegion = function(mgr, config){
45216 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45218 this.split.placement = Roo.SplitBar.RIGHT;
45219 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45220 this.split.el.addClass("x-layout-split-h");
45222 var size = config.initialSize || config.width;
45223 if(typeof size != "undefined"){
45224 this.el.setWidth(size);
45227 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45228 orientation: Roo.SplitBar.HORIZONTAL,
45229 getBox : function(){
45230 if(this.collapsed){
45231 return this.collapsedEl.getBox();
45233 var box = this.el.getBox();
45235 var sw = this.split.el.getWidth();
45242 updateBox : function(box){
45243 if(this.split && !this.collapsed){
45244 var sw = this.split.el.getWidth();
45246 this.split.el.setLeft(box.x);
45247 this.split.el.setTop(box.y);
45248 this.split.el.setHeight(box.height);
45251 if(this.collapsed){
45252 this.updateBody(null, box.height);
45254 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45258 Roo.WestLayoutRegion = function(mgr, config){
45259 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45261 this.split.placement = Roo.SplitBar.LEFT;
45262 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45263 this.split.el.addClass("x-layout-split-h");
45265 var size = config.initialSize || config.width;
45266 if(typeof size != "undefined"){
45267 this.el.setWidth(size);
45270 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45271 orientation: Roo.SplitBar.HORIZONTAL,
45272 getBox : function(){
45273 if(this.collapsed){
45274 return this.collapsedEl.getBox();
45276 var box = this.el.getBox();
45278 box.width += this.split.el.getWidth();
45283 updateBox : function(box){
45284 if(this.split && !this.collapsed){
45285 var sw = this.split.el.getWidth();
45287 this.split.el.setLeft(box.x+box.width);
45288 this.split.el.setTop(box.y);
45289 this.split.el.setHeight(box.height);
45291 if(this.collapsed){
45292 this.updateBody(null, box.height);
45294 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45299 * Ext JS Library 1.1.1
45300 * Copyright(c) 2006-2007, Ext JS, LLC.
45302 * Originally Released Under LGPL - original licence link has changed is not relivant.
45305 * <script type="text/javascript">
45310 * Private internal class for reading and applying state
45312 Roo.LayoutStateManager = function(layout){
45313 // default empty state
45322 Roo.LayoutStateManager.prototype = {
45323 init : function(layout, provider){
45324 this.provider = provider;
45325 var state = provider.get(layout.id+"-layout-state");
45327 var wasUpdating = layout.isUpdating();
45329 layout.beginUpdate();
45331 for(var key in state){
45332 if(typeof state[key] != "function"){
45333 var rstate = state[key];
45334 var r = layout.getRegion(key);
45337 r.resizeTo(rstate.size);
45339 if(rstate.collapsed == true){
45342 r.expand(null, true);
45348 layout.endUpdate();
45350 this.state = state;
45352 this.layout = layout;
45353 layout.on("regionresized", this.onRegionResized, this);
45354 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45355 layout.on("regionexpanded", this.onRegionExpanded, this);
45358 storeState : function(){
45359 this.provider.set(this.layout.id+"-layout-state", this.state);
45362 onRegionResized : function(region, newSize){
45363 this.state[region.getPosition()].size = newSize;
45367 onRegionCollapsed : function(region){
45368 this.state[region.getPosition()].collapsed = true;
45372 onRegionExpanded : function(region){
45373 this.state[region.getPosition()].collapsed = false;
45378 * Ext JS Library 1.1.1
45379 * Copyright(c) 2006-2007, Ext JS, LLC.
45381 * Originally Released Under LGPL - original licence link has changed is not relivant.
45384 * <script type="text/javascript">
45387 * @class Roo.ContentPanel
45388 * @extends Roo.util.Observable
45389 * A basic ContentPanel element.
45390 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45391 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45392 * @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
45393 * @cfg {Boolean} closable True if the panel can be closed/removed
45394 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45395 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45396 * @cfg {Toolbar} toolbar A toolbar for this panel
45397 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45398 * @cfg {String} title The title for this panel
45399 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45400 * @cfg {String} url Calls {@link #setUrl} with this value
45401 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45402 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45403 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45405 * Create a new ContentPanel.
45406 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45407 * @param {String/Object} config A string to set only the title or a config object
45408 * @param {String} content (optional) Set the HTML content for this panel
45409 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45411 Roo.ContentPanel = function(el, config, content){
45415 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45419 if (config && config.parentLayout) {
45420 el = config.parentLayout.el.createChild();
45423 if(el.autoCreate){ // xtype is available if this is called from factory
45427 this.el = Roo.get(el);
45428 if(!this.el && config && config.autoCreate){
45429 if(typeof config.autoCreate == "object"){
45430 if(!config.autoCreate.id){
45431 config.autoCreate.id = config.id||el;
45433 this.el = Roo.DomHelper.append(document.body,
45434 config.autoCreate, true);
45436 this.el = Roo.DomHelper.append(document.body,
45437 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45440 this.closable = false;
45441 this.loaded = false;
45442 this.active = false;
45443 if(typeof config == "string"){
45444 this.title = config;
45446 Roo.apply(this, config);
45449 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45450 this.wrapEl = this.el.wrap();
45451 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45458 this.resizeEl = Roo.get(this.resizeEl, true);
45460 this.resizeEl = this.el;
45465 * Fires when this panel is activated.
45466 * @param {Roo.ContentPanel} this
45470 * @event deactivate
45471 * Fires when this panel is activated.
45472 * @param {Roo.ContentPanel} this
45474 "deactivate" : true,
45478 * Fires when this panel is resized if fitToFrame is true.
45479 * @param {Roo.ContentPanel} this
45480 * @param {Number} width The width after any component adjustments
45481 * @param {Number} height The height after any component adjustments
45485 if(this.autoScroll){
45486 this.resizeEl.setStyle("overflow", "auto");
45488 // fix randome scrolling
45489 this.el.on('scroll', function() {
45490 this.scrollTo('top',0);
45493 content = content || this.content;
45495 this.setContent(content);
45497 if(config && config.url){
45498 this.setUrl(this.url, this.params, this.loadOnce);
45503 Roo.ContentPanel.superclass.constructor.call(this);
45506 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45508 setRegion : function(region){
45509 this.region = region;
45511 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45513 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45518 * Returns the toolbar for this Panel if one was configured.
45519 * @return {Roo.Toolbar}
45521 getToolbar : function(){
45522 return this.toolbar;
45525 setActiveState : function(active){
45526 this.active = active;
45528 this.fireEvent("deactivate", this);
45530 this.fireEvent("activate", this);
45534 * Updates this panel's element
45535 * @param {String} content The new content
45536 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45538 setContent : function(content, loadScripts){
45539 this.el.update(content, loadScripts);
45542 ignoreResize : function(w, h){
45543 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45546 this.lastSize = {width: w, height: h};
45551 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45552 * @return {Roo.UpdateManager} The UpdateManager
45554 getUpdateManager : function(){
45555 return this.el.getUpdateManager();
45558 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45559 * @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:
45562 url: "your-url.php",
45563 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45564 callback: yourFunction,
45565 scope: yourObject, //(optional scope)
45568 text: "Loading...",
45573 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45574 * 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.
45575 * @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}
45576 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45577 * @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.
45578 * @return {Roo.ContentPanel} this
45581 var um = this.el.getUpdateManager();
45582 um.update.apply(um, arguments);
45588 * 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.
45589 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45590 * @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)
45591 * @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)
45592 * @return {Roo.UpdateManager} The UpdateManager
45594 setUrl : function(url, params, loadOnce){
45595 if(this.refreshDelegate){
45596 this.removeListener("activate", this.refreshDelegate);
45598 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45599 this.on("activate", this.refreshDelegate);
45600 return this.el.getUpdateManager();
45603 _handleRefresh : function(url, params, loadOnce){
45604 if(!loadOnce || !this.loaded){
45605 var updater = this.el.getUpdateManager();
45606 updater.update(url, params, this._setLoaded.createDelegate(this));
45610 _setLoaded : function(){
45611 this.loaded = true;
45615 * Returns this panel's id
45618 getId : function(){
45623 * Returns this panel's element - used by regiosn to add.
45624 * @return {Roo.Element}
45626 getEl : function(){
45627 return this.wrapEl || this.el;
45630 adjustForComponents : function(width, height){
45631 if(this.resizeEl != this.el){
45632 width -= this.el.getFrameWidth('lr');
45633 height -= this.el.getFrameWidth('tb');
45636 var te = this.toolbar.getEl();
45637 height -= te.getHeight();
45638 te.setWidth(width);
45640 if(this.adjustments){
45641 width += this.adjustments[0];
45642 height += this.adjustments[1];
45644 return {"width": width, "height": height};
45647 setSize : function(width, height){
45648 if(this.fitToFrame && !this.ignoreResize(width, height)){
45649 if(this.fitContainer && this.resizeEl != this.el){
45650 this.el.setSize(width, height);
45652 var size = this.adjustForComponents(width, height);
45653 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45654 this.fireEvent('resize', this, size.width, size.height);
45659 * Returns this panel's title
45662 getTitle : function(){
45667 * Set this panel's title
45668 * @param {String} title
45670 setTitle : function(title){
45671 this.title = title;
45673 this.region.updatePanelTitle(this, title);
45678 * Returns true is this panel was configured to be closable
45679 * @return {Boolean}
45681 isClosable : function(){
45682 return this.closable;
45685 beforeSlide : function(){
45687 this.resizeEl.clip();
45690 afterSlide : function(){
45692 this.resizeEl.unclip();
45696 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45697 * Will fail silently if the {@link #setUrl} method has not been called.
45698 * This does not activate the panel, just updates its content.
45700 refresh : function(){
45701 if(this.refreshDelegate){
45702 this.loaded = false;
45703 this.refreshDelegate();
45708 * Destroys this panel
45710 destroy : function(){
45711 this.el.removeAllListeners();
45712 var tempEl = document.createElement("span");
45713 tempEl.appendChild(this.el.dom);
45714 tempEl.innerHTML = "";
45720 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45730 * @param {Object} cfg Xtype definition of item to add.
45733 addxtype : function(cfg) {
45735 if (cfg.xtype.match(/^Form$/)) {
45736 var el = this.el.createChild();
45738 this.form = new Roo.form.Form(cfg);
45741 if ( this.form.allItems.length) this.form.render(el.dom);
45744 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45746 cfg.el = this.el.appendChild(document.createElement("div"));
45748 var ret = new Roo[cfg.xtype](cfg);
45749 ret.render(false, ''); // render blank..
45759 * @class Roo.GridPanel
45760 * @extends Roo.ContentPanel
45762 * Create a new GridPanel.
45763 * @param {Roo.grid.Grid} grid The grid for this panel
45764 * @param {String/Object} config A string to set only the panel's title, or a config object
45766 Roo.GridPanel = function(grid, config){
45769 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45770 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45772 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45774 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45777 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45779 // xtype created footer. - not sure if will work as we normally have to render first..
45780 if (this.footer && !this.footer.el && this.footer.xtype) {
45782 this.footer.container = this.grid.getView().getFooterPanel(true);
45783 this.footer.dataSource = this.grid.dataSource;
45784 this.footer = Roo.factory(this.footer, Roo);
45788 grid.monitorWindowResize = false; // turn off autosizing
45789 grid.autoHeight = false;
45790 grid.autoWidth = false;
45792 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45795 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45796 getId : function(){
45797 return this.grid.id;
45801 * Returns the grid for this panel
45802 * @return {Roo.grid.Grid}
45804 getGrid : function(){
45808 setSize : function(width, height){
45809 if(!this.ignoreResize(width, height)){
45810 var grid = this.grid;
45811 var size = this.adjustForComponents(width, height);
45812 grid.getGridEl().setSize(size.width, size.height);
45817 beforeSlide : function(){
45818 this.grid.getView().scroller.clip();
45821 afterSlide : function(){
45822 this.grid.getView().scroller.unclip();
45825 destroy : function(){
45826 this.grid.destroy();
45828 Roo.GridPanel.superclass.destroy.call(this);
45834 * @class Roo.NestedLayoutPanel
45835 * @extends Roo.ContentPanel
45837 * Create a new NestedLayoutPanel.
45840 * @param {Roo.BorderLayout} layout The layout for this panel
45841 * @param {String/Object} config A string to set only the title or a config object
45843 Roo.NestedLayoutPanel = function(layout, config)
45845 // construct with only one argument..
45846 /* FIXME - implement nicer consturctors
45847 if (layout.layout) {
45849 layout = config.layout;
45850 delete config.layout;
45852 if (layout.xtype && !layout.getEl) {
45853 // then layout needs constructing..
45854 layout = Roo.factory(layout, Roo);
45859 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
45861 layout.monitorWindowResize = false; // turn off autosizing
45862 this.layout = layout;
45863 this.layout.getEl().addClass("x-layout-nested-layout");
45870 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45872 setSize : function(width, height){
45873 if(!this.ignoreResize(width, height)){
45874 var size = this.adjustForComponents(width, height);
45875 var el = this.layout.getEl();
45876 el.setSize(size.width, size.height);
45877 var touch = el.dom.offsetWidth;
45878 this.layout.layout();
45879 // ie requires a double layout on the first pass
45880 if(Roo.isIE && !this.initialized){
45881 this.initialized = true;
45882 this.layout.layout();
45887 // activate all subpanels if not currently active..
45889 setActiveState : function(active){
45890 this.active = active;
45892 this.fireEvent("deactivate", this);
45896 this.fireEvent("activate", this);
45897 // not sure if this should happen before or after..
45898 if (!this.layout) {
45899 return; // should not happen..
45902 for (var r in this.layout.regions) {
45903 reg = this.layout.getRegion(r);
45904 if (reg.getActivePanel()) {
45905 //reg.showPanel(reg.getActivePanel()); // force it to activate..
45906 reg.setActivePanel(reg.getActivePanel());
45909 if (!reg.panels.length) {
45912 reg.showPanel(reg.getPanel(0));
45921 * Returns the nested BorderLayout for this panel
45922 * @return {Roo.BorderLayout}
45924 getLayout : function(){
45925 return this.layout;
45929 * Adds a xtype elements to the layout of the nested panel
45933 xtype : 'ContentPanel',
45940 xtype : 'NestedLayoutPanel',
45946 items : [ ... list of content panels or nested layout panels.. ]
45950 * @param {Object} cfg Xtype definition of item to add.
45952 addxtype : function(cfg) {
45953 return this.layout.addxtype(cfg);
45958 Roo.ScrollPanel = function(el, config, content){
45959 config = config || {};
45960 config.fitToFrame = true;
45961 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
45963 this.el.dom.style.overflow = "hidden";
45964 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45965 this.el.removeClass("x-layout-inactive-content");
45966 this.el.on("mousewheel", this.onWheel, this);
45968 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
45969 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
45970 up.unselectable(); down.unselectable();
45971 up.on("click", this.scrollUp, this);
45972 down.on("click", this.scrollDown, this);
45973 up.addClassOnOver("x-scroller-btn-over");
45974 down.addClassOnOver("x-scroller-btn-over");
45975 up.addClassOnClick("x-scroller-btn-click");
45976 down.addClassOnClick("x-scroller-btn-click");
45977 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
45979 this.resizeEl = this.el;
45980 this.el = wrap; this.up = up; this.down = down;
45983 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45985 wheelIncrement : 5,
45986 scrollUp : function(){
45987 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45990 scrollDown : function(){
45991 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45994 afterScroll : function(){
45995 var el = this.resizeEl;
45996 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45997 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45998 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46001 setSize : function(){
46002 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
46003 this.afterScroll();
46006 onWheel : function(e){
46007 var d = e.getWheelDelta();
46008 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
46009 this.afterScroll();
46013 setContent : function(content, loadScripts){
46014 this.resizeEl.update(content, loadScripts);
46028 * @class Roo.TreePanel
46029 * @extends Roo.ContentPanel
46031 * Create a new TreePanel. - defaults to fit/scoll contents.
46032 * @param {String/Object} config A string to set only the panel's title, or a config object
46033 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
46035 Roo.TreePanel = function(config){
46036 var el = config.el;
46037 var tree = config.tree;
46038 delete config.tree;
46039 delete config.el; // hopefull!
46041 // wrapper for IE7 strict & safari scroll issue
46043 var treeEl = el.createChild();
46044 config.resizeEl = treeEl;
46048 Roo.TreePanel.superclass.constructor.call(this, el, config);
46051 this.tree = new Roo.tree.TreePanel(treeEl , tree);
46052 //console.log(tree);
46053 this.on('activate', function()
46055 if (this.tree.rendered) {
46058 //console.log('render tree');
46059 this.tree.render();
46062 this.on('resize', function (cp, w, h) {
46063 this.tree.innerCt.setWidth(w);
46064 this.tree.innerCt.setHeight(h);
46065 this.tree.innerCt.setStyle('overflow-y', 'auto');
46072 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46089 * Ext JS Library 1.1.1
46090 * Copyright(c) 2006-2007, Ext JS, LLC.
46092 * Originally Released Under LGPL - original licence link has changed is not relivant.
46095 * <script type="text/javascript">
46100 * @class Roo.ReaderLayout
46101 * @extends Roo.BorderLayout
46102 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46103 * center region containing two nested regions (a top one for a list view and one for item preview below),
46104 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46105 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46106 * expedites the setup of the overall layout and regions for this common application style.
46109 var reader = new Roo.ReaderLayout();
46110 var CP = Roo.ContentPanel; // shortcut for adding
46112 reader.beginUpdate();
46113 reader.add("north", new CP("north", "North"));
46114 reader.add("west", new CP("west", {title: "West"}));
46115 reader.add("east", new CP("east", {title: "East"}));
46117 reader.regions.listView.add(new CP("listView", "List"));
46118 reader.regions.preview.add(new CP("preview", "Preview"));
46119 reader.endUpdate();
46122 * Create a new ReaderLayout
46123 * @param {Object} config Configuration options
46124 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46125 * document.body if omitted)
46127 Roo.ReaderLayout = function(config, renderTo){
46128 var c = config || {size:{}};
46129 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46130 north: c.north !== false ? Roo.apply({
46134 }, c.north) : false,
46135 west: c.west !== false ? Roo.apply({
46143 margins:{left:5,right:0,bottom:5,top:5},
46144 cmargins:{left:5,right:5,bottom:5,top:5}
46145 }, c.west) : false,
46146 east: c.east !== false ? Roo.apply({
46154 margins:{left:0,right:5,bottom:5,top:5},
46155 cmargins:{left:5,right:5,bottom:5,top:5}
46156 }, c.east) : false,
46157 center: Roo.apply({
46158 tabPosition: 'top',
46162 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46166 this.el.addClass('x-reader');
46168 this.beginUpdate();
46170 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46171 south: c.preview !== false ? Roo.apply({
46178 cmargins:{top:5,left:0, right:0, bottom:0}
46179 }, c.preview) : false,
46180 center: Roo.apply({
46186 this.add('center', new Roo.NestedLayoutPanel(inner,
46187 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46191 this.regions.preview = inner.getRegion('south');
46192 this.regions.listView = inner.getRegion('center');
46195 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46197 * Ext JS Library 1.1.1
46198 * Copyright(c) 2006-2007, Ext JS, LLC.
46200 * Originally Released Under LGPL - original licence link has changed is not relivant.
46203 * <script type="text/javascript">
46207 * @class Roo.grid.Grid
46208 * @extends Roo.util.Observable
46209 * This class represents the primary interface of a component based grid control.
46210 * <br><br>Usage:<pre><code>
46211 var grid = new Roo.grid.Grid("my-container-id", {
46214 selModel: mySelectionModel,
46215 autoSizeColumns: true,
46216 monitorWindowResize: false,
46217 trackMouseOver: true
46222 * <b>Common Problems:</b><br/>
46223 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46224 * element will correct this<br/>
46225 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46226 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46227 * are unpredictable.<br/>
46228 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46229 * grid to calculate dimensions/offsets.<br/>
46231 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46232 * The container MUST have some type of size defined for the grid to fill. The container will be
46233 * automatically set to position relative if it isn't already.
46234 * @param {Object} config A config object that sets properties on this grid.
46236 Roo.grid.Grid = function(container, config){
46237 // initialize the container
46238 this.container = Roo.get(container);
46239 this.container.update("");
46240 this.container.setStyle("overflow", "hidden");
46241 this.container.addClass('x-grid-container');
46243 this.id = this.container.id;
46245 Roo.apply(this, config);
46246 // check and correct shorthanded configs
46248 this.dataSource = this.ds;
46252 this.colModel = this.cm;
46256 this.selModel = this.sm;
46260 if (this.selModel) {
46261 this.selModel = Roo.factory(this.selModel, Roo.grid);
46262 this.sm = this.selModel;
46263 this.sm.xmodule = this.xmodule || false;
46265 if (typeof(this.colModel.config) == 'undefined') {
46266 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46267 this.cm = this.colModel;
46268 this.cm.xmodule = this.xmodule || false;
46270 if (this.dataSource) {
46271 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46272 this.ds = this.dataSource;
46273 this.ds.xmodule = this.xmodule || false;
46280 this.container.setWidth(this.width);
46284 this.container.setHeight(this.height);
46291 * The raw click event for the entire grid.
46292 * @param {Roo.EventObject} e
46297 * The raw dblclick event for the entire grid.
46298 * @param {Roo.EventObject} e
46302 * @event contextmenu
46303 * The raw contextmenu event for the entire grid.
46304 * @param {Roo.EventObject} e
46306 "contextmenu" : true,
46309 * The raw mousedown event for the entire grid.
46310 * @param {Roo.EventObject} e
46312 "mousedown" : true,
46315 * The raw mouseup event for the entire grid.
46316 * @param {Roo.EventObject} e
46321 * The raw mouseover event for the entire grid.
46322 * @param {Roo.EventObject} e
46324 "mouseover" : true,
46327 * The raw mouseout event for the entire grid.
46328 * @param {Roo.EventObject} e
46333 * The raw keypress event for the entire grid.
46334 * @param {Roo.EventObject} e
46339 * The raw keydown event for the entire grid.
46340 * @param {Roo.EventObject} e
46348 * Fires when a cell is clicked
46349 * @param {Grid} this
46350 * @param {Number} rowIndex
46351 * @param {Number} columnIndex
46352 * @param {Roo.EventObject} e
46354 "cellclick" : true,
46356 * @event celldblclick
46357 * Fires when a cell is double clicked
46358 * @param {Grid} this
46359 * @param {Number} rowIndex
46360 * @param {Number} columnIndex
46361 * @param {Roo.EventObject} e
46363 "celldblclick" : true,
46366 * Fires when a row is clicked
46367 * @param {Grid} this
46368 * @param {Number} rowIndex
46369 * @param {Roo.EventObject} e
46373 * @event rowdblclick
46374 * Fires when a row is double clicked
46375 * @param {Grid} this
46376 * @param {Number} rowIndex
46377 * @param {Roo.EventObject} e
46379 "rowdblclick" : true,
46381 * @event headerclick
46382 * Fires when a header is clicked
46383 * @param {Grid} this
46384 * @param {Number} columnIndex
46385 * @param {Roo.EventObject} e
46387 "headerclick" : true,
46389 * @event headerdblclick
46390 * Fires when a header cell is double clicked
46391 * @param {Grid} this
46392 * @param {Number} columnIndex
46393 * @param {Roo.EventObject} e
46395 "headerdblclick" : true,
46397 * @event rowcontextmenu
46398 * Fires when a row is right clicked
46399 * @param {Grid} this
46400 * @param {Number} rowIndex
46401 * @param {Roo.EventObject} e
46403 "rowcontextmenu" : true,
46405 * @event cellcontextmenu
46406 * Fires when a cell is right clicked
46407 * @param {Grid} this
46408 * @param {Number} rowIndex
46409 * @param {Number} cellIndex
46410 * @param {Roo.EventObject} e
46412 "cellcontextmenu" : true,
46414 * @event headercontextmenu
46415 * Fires when a header is right clicked
46416 * @param {Grid} this
46417 * @param {Number} columnIndex
46418 * @param {Roo.EventObject} e
46420 "headercontextmenu" : true,
46422 * @event bodyscroll
46423 * Fires when the body element is scrolled
46424 * @param {Number} scrollLeft
46425 * @param {Number} scrollTop
46427 "bodyscroll" : true,
46429 * @event columnresize
46430 * Fires when the user resizes a column
46431 * @param {Number} columnIndex
46432 * @param {Number} newSize
46434 "columnresize" : true,
46436 * @event columnmove
46437 * Fires when the user moves a column
46438 * @param {Number} oldIndex
46439 * @param {Number} newIndex
46441 "columnmove" : true,
46444 * Fires when row(s) start being dragged
46445 * @param {Grid} this
46446 * @param {Roo.GridDD} dd The drag drop object
46447 * @param {event} e The raw browser event
46449 "startdrag" : true,
46452 * Fires when a drag operation is complete
46453 * @param {Grid} this
46454 * @param {Roo.GridDD} dd The drag drop object
46455 * @param {event} e The raw browser event
46460 * Fires when dragged row(s) are dropped on a valid DD target
46461 * @param {Grid} this
46462 * @param {Roo.GridDD} dd The drag drop object
46463 * @param {String} targetId The target drag drop object
46464 * @param {event} e The raw browser event
46469 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46470 * @param {Grid} this
46471 * @param {Roo.GridDD} dd The drag drop object
46472 * @param {String} targetId The target drag drop object
46473 * @param {event} e The raw browser event
46478 * Fires when the dragged row(s) first cross another DD target while being dragged
46479 * @param {Grid} this
46480 * @param {Roo.GridDD} dd The drag drop object
46481 * @param {String} targetId The target drag drop object
46482 * @param {event} e The raw browser event
46484 "dragenter" : true,
46487 * Fires when the dragged row(s) leave another DD target while being dragged
46488 * @param {Grid} this
46489 * @param {Roo.GridDD} dd The drag drop object
46490 * @param {String} targetId The target drag drop object
46491 * @param {event} e The raw browser event
46496 * Fires when a row is rendered, so you can change add a style to it.
46497 * @param {GridView} gridview The grid view
46498 * @param {Object} rowcfg contains record, rowIndex and rowClass - set rowClass to add a style.
46504 * Fires when the grid is rendered
46505 * @param {Grid} grid
46510 Roo.grid.Grid.superclass.constructor.call(this);
46512 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46515 * @cfg {String} ddGroup - drag drop group.
46519 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46521 minColumnWidth : 25,
46524 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46525 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46526 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46528 autoSizeColumns : false,
46531 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46533 autoSizeHeaders : true,
46536 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46538 monitorWindowResize : true,
46541 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46542 * rows measured to get a columns size. Default is 0 (all rows).
46544 maxRowsToMeasure : 0,
46547 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46549 trackMouseOver : true,
46552 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46556 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46558 enableDragDrop : false,
46561 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46563 enableColumnMove : true,
46566 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46568 enableColumnHide : true,
46571 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46573 enableRowHeightSync : false,
46576 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46581 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46583 autoHeight : false,
46586 * @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.
46588 autoExpandColumn : false,
46591 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46594 autoExpandMin : 50,
46597 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46599 autoExpandMax : 1000,
46602 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46607 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46611 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46618 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46619 * of a fixed width. Default is false.
46622 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46625 * Called once after all setup has been completed and the grid is ready to be rendered.
46626 * @return {Roo.grid.Grid} this
46628 render : function(){
46629 var c = this.container;
46630 // try to detect autoHeight/width mode
46631 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46632 this.autoHeight = true;
46634 var view = this.getView();
46637 c.on("click", this.onClick, this);
46638 c.on("dblclick", this.onDblClick, this);
46639 c.on("contextmenu", this.onContextMenu, this);
46640 c.on("keydown", this.onKeyDown, this);
46642 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46644 this.getSelectionModel().init(this);
46649 this.loadMask = new Roo.LoadMask(this.container,
46650 Roo.apply({store:this.dataSource}, this.loadMask));
46654 if (this.toolbar && this.toolbar.xtype) {
46655 this.toolbar.container = this.getView().getHeaderPanel(true);
46656 this.toolbar = new Ext.Toolbar(this.toolbar);
46658 if (this.footer && this.footer.xtype) {
46659 this.footer.dataSource = this.getDataSource();
46660 this.footer.container = this.getView().getFooterPanel(true);
46661 this.footer = Roo.factory(this.footer, Roo);
46663 if (this.dropTarget && this.dropTarget.xtype) {
46664 delete this.dropTarget.xtype;
46665 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46669 this.rendered = true;
46670 this.fireEvent('render', this);
46675 * Reconfigures the grid to use a different Store and Column Model.
46676 * The View will be bound to the new objects and refreshed.
46677 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46678 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46680 reconfigure : function(dataSource, colModel){
46682 this.loadMask.destroy();
46683 this.loadMask = new Roo.LoadMask(this.container,
46684 Roo.apply({store:dataSource}, this.loadMask));
46686 this.view.bind(dataSource, colModel);
46687 this.dataSource = dataSource;
46688 this.colModel = colModel;
46689 this.view.refresh(true);
46693 onKeyDown : function(e){
46694 this.fireEvent("keydown", e);
46698 * Destroy this grid.
46699 * @param {Boolean} removeEl True to remove the element
46701 destroy : function(removeEl, keepListeners){
46703 this.loadMask.destroy();
46705 var c = this.container;
46706 c.removeAllListeners();
46707 this.view.destroy();
46708 this.colModel.purgeListeners();
46709 if(!keepListeners){
46710 this.purgeListeners();
46713 if(removeEl === true){
46719 processEvent : function(name, e){
46720 this.fireEvent(name, e);
46721 var t = e.getTarget();
46723 var header = v.findHeaderIndex(t);
46724 if(header !== false){
46725 this.fireEvent("header" + name, this, header, e);
46727 var row = v.findRowIndex(t);
46728 var cell = v.findCellIndex(t);
46730 this.fireEvent("row" + name, this, row, e);
46731 if(cell !== false){
46732 this.fireEvent("cell" + name, this, row, cell, e);
46739 onClick : function(e){
46740 this.processEvent("click", e);
46744 onContextMenu : function(e, t){
46745 this.processEvent("contextmenu", e);
46749 onDblClick : function(e){
46750 this.processEvent("dblclick", e);
46754 walkCells : function(row, col, step, fn, scope){
46755 var cm = this.colModel, clen = cm.getColumnCount();
46756 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46768 if(fn.call(scope || this, row, col, cm) === true){
46786 if(fn.call(scope || this, row, col, cm) === true){
46798 getSelections : function(){
46799 return this.selModel.getSelections();
46803 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46804 * but if manual update is required this method will initiate it.
46806 autoSize : function(){
46808 this.view.layout();
46809 if(this.view.adjustForScroll){
46810 this.view.adjustForScroll();
46816 * Returns the grid's underlying element.
46817 * @return {Element} The element
46819 getGridEl : function(){
46820 return this.container;
46823 // private for compatibility, overridden by editor grid
46824 stopEditing : function(){},
46827 * Returns the grid's SelectionModel.
46828 * @return {SelectionModel}
46830 getSelectionModel : function(){
46831 if(!this.selModel){
46832 this.selModel = new Roo.grid.RowSelectionModel();
46834 return this.selModel;
46838 * Returns the grid's DataSource.
46839 * @return {DataSource}
46841 getDataSource : function(){
46842 return this.dataSource;
46846 * Returns the grid's ColumnModel.
46847 * @return {ColumnModel}
46849 getColumnModel : function(){
46850 return this.colModel;
46854 * Returns the grid's GridView object.
46855 * @return {GridView}
46857 getView : function(){
46859 this.view = new Roo.grid.GridView(this.viewConfig);
46864 * Called to get grid's drag proxy text, by default returns this.ddText.
46867 getDragDropText : function(){
46868 var count = this.selModel.getCount();
46869 return String.format(this.ddText, count, count == 1 ? '' : 's');
46873 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46874 * %0 is replaced with the number of selected rows.
46877 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
46879 * Ext JS Library 1.1.1
46880 * Copyright(c) 2006-2007, Ext JS, LLC.
46882 * Originally Released Under LGPL - original licence link has changed is not relivant.
46885 * <script type="text/javascript">
46888 Roo.grid.AbstractGridView = function(){
46892 "beforerowremoved" : true,
46893 "beforerowsinserted" : true,
46894 "beforerefresh" : true,
46895 "rowremoved" : true,
46896 "rowsinserted" : true,
46897 "rowupdated" : true,
46900 Roo.grid.AbstractGridView.superclass.constructor.call(this);
46903 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46904 rowClass : "x-grid-row",
46905 cellClass : "x-grid-cell",
46906 tdClass : "x-grid-td",
46907 hdClass : "x-grid-hd",
46908 splitClass : "x-grid-hd-split",
46910 init: function(grid){
46912 var cid = this.grid.getGridEl().id;
46913 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
46914 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
46915 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
46916 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
46919 getColumnRenderers : function(){
46920 var renderers = [];
46921 var cm = this.grid.colModel;
46922 var colCount = cm.getColumnCount();
46923 for(var i = 0; i < colCount; i++){
46924 renderers[i] = cm.getRenderer(i);
46929 getColumnIds : function(){
46931 var cm = this.grid.colModel;
46932 var colCount = cm.getColumnCount();
46933 for(var i = 0; i < colCount; i++){
46934 ids[i] = cm.getColumnId(i);
46939 getDataIndexes : function(){
46940 if(!this.indexMap){
46941 this.indexMap = this.buildIndexMap();
46943 return this.indexMap.colToData;
46946 getColumnIndexByDataIndex : function(dataIndex){
46947 if(!this.indexMap){
46948 this.indexMap = this.buildIndexMap();
46950 return this.indexMap.dataToCol[dataIndex];
46954 * Set a css style for a column dynamically.
46955 * @param {Number} colIndex The index of the column
46956 * @param {String} name The css property name
46957 * @param {String} value The css value
46959 setCSSStyle : function(colIndex, name, value){
46960 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
46961 Roo.util.CSS.updateRule(selector, name, value);
46964 generateRules : function(cm){
46965 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46966 Roo.util.CSS.removeStyleSheet(rulesId);
46967 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46968 var cid = cm.getColumnId(i);
46969 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
46970 this.tdSelector, cid, " {\n}\n",
46971 this.hdSelector, cid, " {\n}\n",
46972 this.splitSelector, cid, " {\n}\n");
46974 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46978 * Ext JS Library 1.1.1
46979 * Copyright(c) 2006-2007, Ext JS, LLC.
46981 * Originally Released Under LGPL - original licence link has changed is not relivant.
46984 * <script type="text/javascript">
46988 // This is a support class used internally by the Grid components
46989 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
46991 this.view = grid.getView();
46992 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46993 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46995 this.setHandleElId(Roo.id(hd));
46996 this.setOuterHandleElId(Roo.id(hd2));
46998 this.scroll = false;
47000 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
47002 getDragData : function(e){
47003 var t = Roo.lib.Event.getTarget(e);
47004 var h = this.view.findHeaderCell(t);
47006 return {ddel: h.firstChild, header:h};
47011 onInitDrag : function(e){
47012 this.view.headersDisabled = true;
47013 var clone = this.dragData.ddel.cloneNode(true);
47014 clone.id = Roo.id();
47015 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
47016 this.proxy.update(clone);
47020 afterValidDrop : function(){
47022 setTimeout(function(){
47023 v.headersDisabled = false;
47027 afterInvalidDrop : function(){
47029 setTimeout(function(){
47030 v.headersDisabled = false;
47036 * Ext JS Library 1.1.1
47037 * Copyright(c) 2006-2007, Ext JS, LLC.
47039 * Originally Released Under LGPL - original licence link has changed is not relivant.
47042 * <script type="text/javascript">
47045 // This is a support class used internally by the Grid components
47046 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
47048 this.view = grid.getView();
47049 // split the proxies so they don't interfere with mouse events
47050 this.proxyTop = Roo.DomHelper.append(document.body, {
47051 cls:"col-move-top", html:" "
47053 this.proxyBottom = Roo.DomHelper.append(document.body, {
47054 cls:"col-move-bottom", html:" "
47056 this.proxyTop.hide = this.proxyBottom.hide = function(){
47057 this.setLeftTop(-100,-100);
47058 this.setStyle("visibility", "hidden");
47060 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47061 // temporarily disabled
47062 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47063 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47065 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47066 proxyOffsets : [-4, -9],
47067 fly: Roo.Element.fly,
47069 getTargetFromEvent : function(e){
47070 var t = Roo.lib.Event.getTarget(e);
47071 var cindex = this.view.findCellIndex(t);
47072 if(cindex !== false){
47073 return this.view.getHeaderCell(cindex);
47077 nextVisible : function(h){
47078 var v = this.view, cm = this.grid.colModel;
47081 if(!cm.isHidden(v.getCellIndex(h))){
47089 prevVisible : function(h){
47090 var v = this.view, cm = this.grid.colModel;
47093 if(!cm.isHidden(v.getCellIndex(h))){
47101 positionIndicator : function(h, n, e){
47102 var x = Roo.lib.Event.getPageX(e);
47103 var r = Roo.lib.Dom.getRegion(n.firstChild);
47104 var px, pt, py = r.top + this.proxyOffsets[1];
47105 if((r.right - x) <= (r.right-r.left)/2){
47106 px = r.right+this.view.borderWidth;
47112 var oldIndex = this.view.getCellIndex(h);
47113 var newIndex = this.view.getCellIndex(n);
47115 if(this.grid.colModel.isFixed(newIndex)){
47119 var locked = this.grid.colModel.isLocked(newIndex);
47124 if(oldIndex < newIndex){
47127 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47130 px += this.proxyOffsets[0];
47131 this.proxyTop.setLeftTop(px, py);
47132 this.proxyTop.show();
47133 if(!this.bottomOffset){
47134 this.bottomOffset = this.view.mainHd.getHeight();
47136 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47137 this.proxyBottom.show();
47141 onNodeEnter : function(n, dd, e, data){
47142 if(data.header != n){
47143 this.positionIndicator(data.header, n, e);
47147 onNodeOver : function(n, dd, e, data){
47148 var result = false;
47149 if(data.header != n){
47150 result = this.positionIndicator(data.header, n, e);
47153 this.proxyTop.hide();
47154 this.proxyBottom.hide();
47156 return result ? this.dropAllowed : this.dropNotAllowed;
47159 onNodeOut : function(n, dd, e, data){
47160 this.proxyTop.hide();
47161 this.proxyBottom.hide();
47164 onNodeDrop : function(n, dd, e, data){
47165 var h = data.header;
47167 var cm = this.grid.colModel;
47168 var x = Roo.lib.Event.getPageX(e);
47169 var r = Roo.lib.Dom.getRegion(n.firstChild);
47170 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47171 var oldIndex = this.view.getCellIndex(h);
47172 var newIndex = this.view.getCellIndex(n);
47173 var locked = cm.isLocked(newIndex);
47177 if(oldIndex < newIndex){
47180 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47183 cm.setLocked(oldIndex, locked, true);
47184 cm.moveColumn(oldIndex, newIndex);
47185 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47193 * Ext JS Library 1.1.1
47194 * Copyright(c) 2006-2007, Ext JS, LLC.
47196 * Originally Released Under LGPL - original licence link has changed is not relivant.
47199 * <script type="text/javascript">
47203 * @class Roo.grid.GridView
47204 * @extends Roo.util.Observable
47207 * @param {Object} config
47209 Roo.grid.GridView = function(config){
47210 Roo.grid.GridView.superclass.constructor.call(this);
47213 Roo.apply(this, config);
47216 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47219 * Override this function to apply custom css classes to rows during rendering
47220 * @param {Record} record The record
47221 * @param {Number} index
47222 * @method getRowClass
47224 rowClass : "x-grid-row",
47226 cellClass : "x-grid-col",
47228 tdClass : "x-grid-td",
47230 hdClass : "x-grid-hd",
47232 splitClass : "x-grid-split",
47234 sortClasses : ["sort-asc", "sort-desc"],
47236 enableMoveAnim : false,
47240 dh : Roo.DomHelper,
47242 fly : Roo.Element.fly,
47244 css : Roo.util.CSS,
47250 scrollIncrement : 22,
47252 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47254 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47256 bind : function(ds, cm){
47258 this.ds.un("load", this.onLoad, this);
47259 this.ds.un("datachanged", this.onDataChange, this);
47260 this.ds.un("add", this.onAdd, this);
47261 this.ds.un("remove", this.onRemove, this);
47262 this.ds.un("update", this.onUpdate, this);
47263 this.ds.un("clear", this.onClear, this);
47266 ds.on("load", this.onLoad, this);
47267 ds.on("datachanged", this.onDataChange, this);
47268 ds.on("add", this.onAdd, this);
47269 ds.on("remove", this.onRemove, this);
47270 ds.on("update", this.onUpdate, this);
47271 ds.on("clear", this.onClear, this);
47276 this.cm.un("widthchange", this.onColWidthChange, this);
47277 this.cm.un("headerchange", this.onHeaderChange, this);
47278 this.cm.un("hiddenchange", this.onHiddenChange, this);
47279 this.cm.un("columnmoved", this.onColumnMove, this);
47280 this.cm.un("columnlockchange", this.onColumnLock, this);
47283 this.generateRules(cm);
47284 cm.on("widthchange", this.onColWidthChange, this);
47285 cm.on("headerchange", this.onHeaderChange, this);
47286 cm.on("hiddenchange", this.onHiddenChange, this);
47287 cm.on("columnmoved", this.onColumnMove, this);
47288 cm.on("columnlockchange", this.onColumnLock, this);
47293 init: function(grid){
47294 Roo.grid.GridView.superclass.init.call(this, grid);
47296 this.bind(grid.dataSource, grid.colModel);
47298 grid.on("headerclick", this.handleHeaderClick, this);
47300 if(grid.trackMouseOver){
47301 grid.on("mouseover", this.onRowOver, this);
47302 grid.on("mouseout", this.onRowOut, this);
47304 grid.cancelTextSelection = function(){};
47305 this.gridId = grid.id;
47307 var tpls = this.templates || {};
47310 tpls.master = new Roo.Template(
47311 '<div class="x-grid" hidefocus="true">',
47312 '<div class="x-grid-topbar"></div>',
47313 '<div class="x-grid-scroller"><div></div></div>',
47314 '<div class="x-grid-locked">',
47315 '<div class="x-grid-header">{lockedHeader}</div>',
47316 '<div class="x-grid-body">{lockedBody}</div>',
47318 '<div class="x-grid-viewport">',
47319 '<div class="x-grid-header">{header}</div>',
47320 '<div class="x-grid-body">{body}</div>',
47322 '<div class="x-grid-bottombar"></div>',
47323 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47324 '<div class="x-grid-resize-proxy"> </div>',
47327 tpls.master.disableformats = true;
47331 tpls.header = new Roo.Template(
47332 '<table border="0" cellspacing="0" cellpadding="0">',
47333 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47336 tpls.header.disableformats = true;
47338 tpls.header.compile();
47341 tpls.hcell = new Roo.Template(
47342 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47343 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47346 tpls.hcell.disableFormats = true;
47348 tpls.hcell.compile();
47351 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47352 tpls.hsplit.disableFormats = true;
47354 tpls.hsplit.compile();
47357 tpls.body = new Roo.Template(
47358 '<table border="0" cellspacing="0" cellpadding="0">',
47359 "<tbody>{rows}</tbody>",
47362 tpls.body.disableFormats = true;
47364 tpls.body.compile();
47367 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47368 tpls.row.disableFormats = true;
47370 tpls.row.compile();
47373 tpls.cell = new Roo.Template(
47374 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47375 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47378 tpls.cell.disableFormats = true;
47380 tpls.cell.compile();
47382 this.templates = tpls;
47385 // remap these for backwards compat
47386 onColWidthChange : function(){
47387 this.updateColumns.apply(this, arguments);
47389 onHeaderChange : function(){
47390 this.updateHeaders.apply(this, arguments);
47392 onHiddenChange : function(){
47393 this.handleHiddenChange.apply(this, arguments);
47395 onColumnMove : function(){
47396 this.handleColumnMove.apply(this, arguments);
47398 onColumnLock : function(){
47399 this.handleLockChange.apply(this, arguments);
47402 onDataChange : function(){
47404 this.updateHeaderSortState();
47407 onClear : function(){
47411 onUpdate : function(ds, record){
47412 this.refreshRow(record);
47415 refreshRow : function(record){
47416 var ds = this.ds, index;
47417 if(typeof record == 'number'){
47419 record = ds.getAt(index);
47421 index = ds.indexOf(record);
47423 this.insertRows(ds, index, index, true);
47424 this.onRemove(ds, record, index+1, true);
47425 this.syncRowHeights(index, index);
47427 this.fireEvent("rowupdated", this, index, record);
47430 onAdd : function(ds, records, index){
47431 this.insertRows(ds, index, index + (records.length-1));
47434 onRemove : function(ds, record, index, isUpdate){
47435 if(isUpdate !== true){
47436 this.fireEvent("beforerowremoved", this, index, record);
47438 var bt = this.getBodyTable(), lt = this.getLockedTable();
47439 if(bt.rows[index]){
47440 bt.firstChild.removeChild(bt.rows[index]);
47442 if(lt.rows[index]){
47443 lt.firstChild.removeChild(lt.rows[index]);
47445 if(isUpdate !== true){
47446 this.stripeRows(index);
47447 this.syncRowHeights(index, index);
47449 this.fireEvent("rowremoved", this, index, record);
47453 onLoad : function(){
47454 this.scrollToTop();
47458 * Scrolls the grid to the top
47460 scrollToTop : function(){
47462 this.scroller.dom.scrollTop = 0;
47468 * Gets a panel in the header of the grid that can be used for toolbars etc.
47469 * After modifying the contents of this panel a call to grid.autoSize() may be
47470 * required to register any changes in size.
47471 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47472 * @return Roo.Element
47474 getHeaderPanel : function(doShow){
47476 this.headerPanel.show();
47478 return this.headerPanel;
47482 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47483 * After modifying the contents of this panel a call to grid.autoSize() may be
47484 * required to register any changes in size.
47485 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47486 * @return Roo.Element
47488 getFooterPanel : function(doShow){
47490 this.footerPanel.show();
47492 return this.footerPanel;
47495 initElements : function(){
47496 var E = Roo.Element;
47497 var el = this.grid.getGridEl().dom.firstChild;
47498 var cs = el.childNodes;
47500 this.el = new E(el);
47501 this.headerPanel = new E(el.firstChild);
47502 this.headerPanel.enableDisplayMode("block");
47504 this.scroller = new E(cs[1]);
47505 this.scrollSizer = new E(this.scroller.dom.firstChild);
47507 this.lockedWrap = new E(cs[2]);
47508 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47509 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47511 this.mainWrap = new E(cs[3]);
47512 this.mainHd = new E(this.mainWrap.dom.firstChild);
47513 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47515 this.footerPanel = new E(cs[4]);
47516 this.footerPanel.enableDisplayMode("block");
47518 this.focusEl = new E(cs[5]);
47519 this.focusEl.swallowEvent("click", true);
47520 this.resizeProxy = new E(cs[6]);
47522 this.headerSelector = String.format(
47523 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47524 this.lockedHd.id, this.mainHd.id
47527 this.splitterSelector = String.format(
47528 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47529 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47532 idToCssName : function(s)
47534 return s.replace(/[^a-z0-9]+/ig, '-');
47537 getHeaderCell : function(index){
47538 return Roo.DomQuery.select(this.headerSelector)[index];
47541 getHeaderCellMeasure : function(index){
47542 return this.getHeaderCell(index).firstChild;
47545 getHeaderCellText : function(index){
47546 return this.getHeaderCell(index).firstChild.firstChild;
47549 getLockedTable : function(){
47550 return this.lockedBody.dom.firstChild;
47553 getBodyTable : function(){
47554 return this.mainBody.dom.firstChild;
47557 getLockedRow : function(index){
47558 return this.getLockedTable().rows[index];
47561 getRow : function(index){
47562 return this.getBodyTable().rows[index];
47565 getRowComposite : function(index){
47567 this.rowEl = new Roo.CompositeElementLite();
47569 var els = [], lrow, mrow;
47570 if(lrow = this.getLockedRow(index)){
47573 if(mrow = this.getRow(index)){
47576 this.rowEl.elements = els;
47580 getCell : function(rowIndex, colIndex){
47581 var locked = this.cm.getLockedCount();
47583 if(colIndex < locked){
47584 source = this.lockedBody.dom.firstChild;
47586 source = this.mainBody.dom.firstChild;
47587 colIndex -= locked;
47589 return source.rows[rowIndex].childNodes[colIndex];
47592 getCellText : function(rowIndex, colIndex){
47593 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47596 getCellBox : function(cell){
47597 var b = this.fly(cell).getBox();
47598 if(Roo.isOpera){ // opera fails to report the Y
47599 b.y = cell.offsetTop + this.mainBody.getY();
47604 getCellIndex : function(cell){
47605 var id = String(cell.className).match(this.cellRE);
47607 return parseInt(id[1], 10);
47612 findHeaderIndex : function(n){
47613 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47614 return r ? this.getCellIndex(r) : false;
47617 findHeaderCell : function(n){
47618 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47619 return r ? r : false;
47622 findRowIndex : function(n){
47626 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47627 return r ? r.rowIndex : false;
47630 findCellIndex : function(node){
47631 var stop = this.el.dom;
47632 while(node && node != stop){
47633 if(this.findRE.test(node.className)){
47634 return this.getCellIndex(node);
47636 node = node.parentNode;
47641 getColumnId : function(index){
47642 return this.cm.getColumnId(index);
47645 getSplitters : function()
47647 if(this.splitterSelector){
47648 return Roo.DomQuery.select(this.splitterSelector);
47654 getSplitter : function(index){
47655 return this.getSplitters()[index];
47658 onRowOver : function(e, t){
47660 if((row = this.findRowIndex(t)) !== false){
47661 this.getRowComposite(row).addClass("x-grid-row-over");
47665 onRowOut : function(e, t){
47667 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47668 this.getRowComposite(row).removeClass("x-grid-row-over");
47672 renderHeaders : function(){
47674 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47675 var cb = [], lb = [], sb = [], lsb = [], p = {};
47676 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47677 p.cellId = "x-grid-hd-0-" + i;
47678 p.splitId = "x-grid-csplit-0-" + i;
47679 p.id = cm.getColumnId(i);
47680 p.title = cm.getColumnTooltip(i) || "";
47681 p.value = cm.getColumnHeader(i) || "";
47682 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47683 if(!cm.isLocked(i)){
47684 cb[cb.length] = ct.apply(p);
47685 sb[sb.length] = st.apply(p);
47687 lb[lb.length] = ct.apply(p);
47688 lsb[lsb.length] = st.apply(p);
47691 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47692 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47695 updateHeaders : function(){
47696 var html = this.renderHeaders();
47697 this.lockedHd.update(html[0]);
47698 this.mainHd.update(html[1]);
47702 * Focuses the specified row.
47703 * @param {Number} row The row index
47705 focusRow : function(row){
47706 var x = this.scroller.dom.scrollLeft;
47707 this.focusCell(row, 0, false);
47708 this.scroller.dom.scrollLeft = x;
47712 * Focuses the specified cell.
47713 * @param {Number} row The row index
47714 * @param {Number} col The column index
47715 * @param {Boolean} hscroll false to disable horizontal scrolling
47717 focusCell : function(row, col, hscroll){
47718 var el = this.ensureVisible(row, col, hscroll);
47719 this.focusEl.alignTo(el, "tl-tl");
47721 this.focusEl.focus();
47723 this.focusEl.focus.defer(1, this.focusEl);
47728 * Scrolls the specified cell into view
47729 * @param {Number} row The row index
47730 * @param {Number} col The column index
47731 * @param {Boolean} hscroll false to disable horizontal scrolling
47733 ensureVisible : function(row, col, hscroll){
47734 if(typeof row != "number"){
47735 row = row.rowIndex;
47737 if(row < 0 && row >= this.ds.getCount()){
47740 col = (col !== undefined ? col : 0);
47741 var cm = this.grid.colModel;
47742 while(cm.isHidden(col)){
47746 var el = this.getCell(row, col);
47750 var c = this.scroller.dom;
47752 var ctop = parseInt(el.offsetTop, 10);
47753 var cleft = parseInt(el.offsetLeft, 10);
47754 var cbot = ctop + el.offsetHeight;
47755 var cright = cleft + el.offsetWidth;
47757 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47758 var stop = parseInt(c.scrollTop, 10);
47759 var sleft = parseInt(c.scrollLeft, 10);
47760 var sbot = stop + ch;
47761 var sright = sleft + c.clientWidth;
47764 c.scrollTop = ctop;
47765 }else if(cbot > sbot){
47766 c.scrollTop = cbot-ch;
47769 if(hscroll !== false){
47771 c.scrollLeft = cleft;
47772 }else if(cright > sright){
47773 c.scrollLeft = cright-c.clientWidth;
47779 updateColumns : function(){
47780 this.grid.stopEditing();
47781 var cm = this.grid.colModel, colIds = this.getColumnIds();
47782 //var totalWidth = cm.getTotalWidth();
47784 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47785 //if(cm.isHidden(i)) continue;
47786 var w = cm.getColumnWidth(i);
47787 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47788 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47790 this.updateSplitters();
47793 generateRules : function(cm){
47794 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
47795 Roo.util.CSS.removeStyleSheet(rulesId);
47796 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47797 var cid = cm.getColumnId(i);
47799 if(cm.config[i].align){
47800 align = 'text-align:'+cm.config[i].align+';';
47803 if(cm.isHidden(i)){
47804 hidden = 'display:none;';
47806 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47808 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47809 this.hdSelector, cid, " {\n", align, width, "}\n",
47810 this.tdSelector, cid, " {\n",hidden,"\n}\n",
47811 this.splitSelector, cid, " {\n", hidden , "\n}\n");
47813 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47816 updateSplitters : function(){
47817 var cm = this.cm, s = this.getSplitters();
47818 if(s){ // splitters not created yet
47819 var pos = 0, locked = true;
47820 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47821 if(cm.isHidden(i)) continue;
47822 var w = cm.getColumnWidth(i); // make sure it's a number
47823 if(!cm.isLocked(i) && locked){
47828 s[i].style.left = (pos-this.splitOffset) + "px";
47833 handleHiddenChange : function(colModel, colIndex, hidden){
47835 this.hideColumn(colIndex);
47837 this.unhideColumn(colIndex);
47841 hideColumn : function(colIndex){
47842 var cid = this.getColumnId(colIndex);
47843 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
47844 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
47846 this.updateHeaders();
47848 this.updateSplitters();
47852 unhideColumn : function(colIndex){
47853 var cid = this.getColumnId(colIndex);
47854 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
47855 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
47858 this.updateHeaders();
47860 this.updateSplitters();
47864 insertRows : function(dm, firstRow, lastRow, isUpdate){
47865 if(firstRow == 0 && lastRow == dm.getCount()-1){
47869 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
47871 var s = this.getScrollState();
47872 var markup = this.renderRows(firstRow, lastRow);
47873 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
47874 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
47875 this.restoreScroll(s);
47877 this.fireEvent("rowsinserted", this, firstRow, lastRow);
47878 this.syncRowHeights(firstRow, lastRow);
47879 this.stripeRows(firstRow);
47885 bufferRows : function(markup, target, index){
47886 var before = null, trows = target.rows, tbody = target.tBodies[0];
47887 if(index < trows.length){
47888 before = trows[index];
47890 var b = document.createElement("div");
47891 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
47892 var rows = b.firstChild.rows;
47893 for(var i = 0, len = rows.length; i < len; i++){
47895 tbody.insertBefore(rows[0], before);
47897 tbody.appendChild(rows[0]);
47904 deleteRows : function(dm, firstRow, lastRow){
47905 if(dm.getRowCount()<1){
47906 this.fireEvent("beforerefresh", this);
47907 this.mainBody.update("");
47908 this.lockedBody.update("");
47909 this.fireEvent("refresh", this);
47911 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
47912 var bt = this.getBodyTable();
47913 var tbody = bt.firstChild;
47914 var rows = bt.rows;
47915 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
47916 tbody.removeChild(rows[firstRow]);
47918 this.stripeRows(firstRow);
47919 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
47923 updateRows : function(dataSource, firstRow, lastRow){
47924 var s = this.getScrollState();
47926 this.restoreScroll(s);
47929 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
47933 this.updateHeaderSortState();
47936 getScrollState : function(){
47937 var sb = this.scroller.dom;
47938 return {left: sb.scrollLeft, top: sb.scrollTop};
47941 stripeRows : function(startRow){
47942 if(!this.grid.stripeRows || this.ds.getCount() < 1){
47945 startRow = startRow || 0;
47946 var rows = this.getBodyTable().rows;
47947 var lrows = this.getLockedTable().rows;
47948 var cls = ' x-grid-row-alt ';
47949 for(var i = startRow, len = rows.length; i < len; i++){
47950 var row = rows[i], lrow = lrows[i];
47951 var isAlt = ((i+1) % 2 == 0);
47952 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
47953 if(isAlt == hasAlt){
47957 row.className += " x-grid-row-alt";
47959 row.className = row.className.replace("x-grid-row-alt", "");
47962 lrow.className = row.className;
47967 restoreScroll : function(state){
47968 var sb = this.scroller.dom;
47969 sb.scrollLeft = state.left;
47970 sb.scrollTop = state.top;
47974 syncScroll : function(){
47975 var sb = this.scroller.dom;
47976 var sh = this.mainHd.dom;
47977 var bs = this.mainBody.dom;
47978 var lv = this.lockedBody.dom;
47979 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47980 lv.scrollTop = bs.scrollTop = sb.scrollTop;
47983 handleScroll : function(e){
47985 var sb = this.scroller.dom;
47986 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47990 handleWheel : function(e){
47991 var d = e.getWheelDelta();
47992 this.scroller.dom.scrollTop -= d*22;
47993 // set this here to prevent jumpy scrolling on large tables
47994 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47998 renderRows : function(startRow, endRow){
47999 // pull in all the crap needed to render rows
48000 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
48001 var colCount = cm.getColumnCount();
48003 if(ds.getCount() < 1){
48007 // build a map for all the columns
48009 for(var i = 0; i < colCount; i++){
48010 var name = cm.getDataIndex(i);
48012 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
48013 renderer : cm.getRenderer(i),
48014 id : cm.getColumnId(i),
48015 locked : cm.isLocked(i)
48019 startRow = startRow || 0;
48020 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
48022 // records to render
48023 var rs = ds.getRange(startRow, endRow);
48025 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
48028 // As much as I hate to duplicate code, this was branched because FireFox really hates
48029 // [].join("") on strings. The performance difference was substantial enough to
48030 // branch this function
48031 doRender : Roo.isGecko ?
48032 function(cs, rs, ds, startRow, colCount, stripe){
48033 var ts = this.templates, ct = ts.cell, rt = ts.row;
48035 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48037 var hasListener = this.grid.hasListener('rowclass');
48039 for(var j = 0, len = rs.length; j < len; j++){
48040 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
48041 for(var i = 0; i < colCount; i++){
48043 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48045 p.css = p.attr = "";
48046 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48047 if(p.value == undefined || p.value === "") p.value = " ";
48048 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48049 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48051 var markup = ct.apply(p);
48059 if(stripe && ((rowIndex+1) % 2 == 0)){
48060 alt.push("x-grid-row-alt")
48063 alt.push( " x-grid-dirty-row");
48066 if(this.getRowClass){
48067 alt.push(this.getRowClass(r, rowIndex));
48073 rowIndex : rowIndex,
48076 this.grid.fireEvent('rowclass', this, rowcfg);
48077 alt.push(rowcfg.rowClass);
48079 rp.alt = alt.join(" ");
48080 lbuf+= rt.apply(rp);
48082 buf+= rt.apply(rp);
48084 return [lbuf, buf];
48086 function(cs, rs, ds, startRow, colCount, stripe){
48087 var ts = this.templates, ct = ts.cell, rt = ts.row;
48089 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48090 var hasListener = this.grid.hasListener('rowclass');
48092 for(var j = 0, len = rs.length; j < len; j++){
48093 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48094 for(var i = 0; i < colCount; i++){
48096 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48098 p.css = p.attr = "";
48099 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48100 if(p.value == undefined || p.value === "") p.value = " ";
48101 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48102 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48104 var markup = ct.apply(p);
48106 cb[cb.length] = markup;
48108 lcb[lcb.length] = markup;
48112 if(stripe && ((rowIndex+1) % 2 == 0)){
48113 alt.push( "x-grid-row-alt");
48116 alt.push(" x-grid-dirty-row");
48119 if(this.getRowClass){
48120 alt.push( this.getRowClass(r, rowIndex));
48126 rowIndex : rowIndex,
48129 this.grid.fireEvent('rowclass', this, rowcfg);
48130 alt.push(rowcfg.rowClass);
48132 rp.alt = alt.join(" ");
48133 rp.cells = lcb.join("");
48134 lbuf[lbuf.length] = rt.apply(rp);
48135 rp.cells = cb.join("");
48136 buf[buf.length] = rt.apply(rp);
48138 return [lbuf.join(""), buf.join("")];
48141 renderBody : function(){
48142 var markup = this.renderRows();
48143 var bt = this.templates.body;
48144 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48148 * Refreshes the grid
48149 * @param {Boolean} headersToo
48151 refresh : function(headersToo){
48152 this.fireEvent("beforerefresh", this);
48153 this.grid.stopEditing();
48154 var result = this.renderBody();
48155 this.lockedBody.update(result[0]);
48156 this.mainBody.update(result[1]);
48157 if(headersToo === true){
48158 this.updateHeaders();
48159 this.updateColumns();
48160 this.updateSplitters();
48161 this.updateHeaderSortState();
48163 this.syncRowHeights();
48165 this.fireEvent("refresh", this);
48168 handleColumnMove : function(cm, oldIndex, newIndex){
48169 this.indexMap = null;
48170 var s = this.getScrollState();
48171 this.refresh(true);
48172 this.restoreScroll(s);
48173 this.afterMove(newIndex);
48176 afterMove : function(colIndex){
48177 if(this.enableMoveAnim && Roo.enableFx){
48178 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48182 updateCell : function(dm, rowIndex, dataIndex){
48183 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48184 if(typeof colIndex == "undefined"){ // not present in grid
48187 var cm = this.grid.colModel;
48188 var cell = this.getCell(rowIndex, colIndex);
48189 var cellText = this.getCellText(rowIndex, colIndex);
48192 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48193 id : cm.getColumnId(colIndex),
48194 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48196 var renderer = cm.getRenderer(colIndex);
48197 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48198 if(typeof val == "undefined" || val === "") val = " ";
48199 cellText.innerHTML = val;
48200 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48201 this.syncRowHeights(rowIndex, rowIndex);
48204 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48206 if(this.grid.autoSizeHeaders){
48207 var h = this.getHeaderCellMeasure(colIndex);
48208 maxWidth = Math.max(maxWidth, h.scrollWidth);
48211 if(this.cm.isLocked(colIndex)){
48212 tb = this.getLockedTable();
48215 tb = this.getBodyTable();
48216 index = colIndex - this.cm.getLockedCount();
48219 var rows = tb.rows;
48220 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48221 for(var i = 0; i < stopIndex; i++){
48222 var cell = rows[i].childNodes[index].firstChild;
48223 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48226 return maxWidth + /*margin for error in IE*/ 5;
48229 * Autofit a column to its content.
48230 * @param {Number} colIndex
48231 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48233 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48234 if(this.cm.isHidden(colIndex)){
48235 return; // can't calc a hidden column
48238 var cid = this.cm.getColumnId(colIndex);
48239 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48240 if(this.grid.autoSizeHeaders){
48241 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48244 var newWidth = this.calcColumnWidth(colIndex);
48245 this.cm.setColumnWidth(colIndex,
48246 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48247 if(!suppressEvent){
48248 this.grid.fireEvent("columnresize", colIndex, newWidth);
48253 * Autofits all columns to their content and then expands to fit any extra space in the grid
48255 autoSizeColumns : function(){
48256 var cm = this.grid.colModel;
48257 var colCount = cm.getColumnCount();
48258 for(var i = 0; i < colCount; i++){
48259 this.autoSizeColumn(i, true, true);
48261 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48264 this.updateColumns();
48270 * Autofits all columns to the grid's width proportionate with their current size
48271 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48273 fitColumns : function(reserveScrollSpace){
48274 var cm = this.grid.colModel;
48275 var colCount = cm.getColumnCount();
48279 for (i = 0; i < colCount; i++){
48280 if(!cm.isHidden(i) && !cm.isFixed(i)){
48281 w = cm.getColumnWidth(i);
48287 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48288 if(reserveScrollSpace){
48291 var frac = (avail - cm.getTotalWidth())/width;
48292 while (cols.length){
48295 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48297 this.updateColumns();
48301 onRowSelect : function(rowIndex){
48302 var row = this.getRowComposite(rowIndex);
48303 row.addClass("x-grid-row-selected");
48306 onRowDeselect : function(rowIndex){
48307 var row = this.getRowComposite(rowIndex);
48308 row.removeClass("x-grid-row-selected");
48311 onCellSelect : function(row, col){
48312 var cell = this.getCell(row, col);
48314 Roo.fly(cell).addClass("x-grid-cell-selected");
48318 onCellDeselect : function(row, col){
48319 var cell = this.getCell(row, col);
48321 Roo.fly(cell).removeClass("x-grid-cell-selected");
48325 updateHeaderSortState : function(){
48326 var state = this.ds.getSortState();
48330 this.sortState = state;
48331 var sortColumn = this.cm.findColumnIndex(state.field);
48332 if(sortColumn != -1){
48333 var sortDir = state.direction;
48334 var sc = this.sortClasses;
48335 var hds = this.el.select(this.headerSelector).removeClass(sc);
48336 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48340 handleHeaderClick : function(g, index){
48341 if(this.headersDisabled){
48344 var dm = g.dataSource, cm = g.colModel;
48345 if(!cm.isSortable(index)){
48349 dm.sort(cm.getDataIndex(index));
48353 destroy : function(){
48355 this.colMenu.removeAll();
48356 Roo.menu.MenuMgr.unregister(this.colMenu);
48357 this.colMenu.getEl().remove();
48358 delete this.colMenu;
48361 this.hmenu.removeAll();
48362 Roo.menu.MenuMgr.unregister(this.hmenu);
48363 this.hmenu.getEl().remove();
48366 if(this.grid.enableColumnMove){
48367 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48369 for(var dd in dds){
48370 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48371 var elid = dds[dd].dragElId;
48373 Roo.get(elid).remove();
48374 } else if(dds[dd].config.isTarget){
48375 dds[dd].proxyTop.remove();
48376 dds[dd].proxyBottom.remove();
48379 if(Roo.dd.DDM.locationCache[dd]){
48380 delete Roo.dd.DDM.locationCache[dd];
48383 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48386 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48387 this.bind(null, null);
48388 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48391 handleLockChange : function(){
48392 this.refresh(true);
48395 onDenyColumnLock : function(){
48399 onDenyColumnHide : function(){
48403 handleHdMenuClick : function(item){
48404 var index = this.hdCtxIndex;
48405 var cm = this.cm, ds = this.ds;
48408 ds.sort(cm.getDataIndex(index), "ASC");
48411 ds.sort(cm.getDataIndex(index), "DESC");
48414 var lc = cm.getLockedCount();
48415 if(cm.getColumnCount(true) <= lc+1){
48416 this.onDenyColumnLock();
48420 cm.setLocked(index, true, true);
48421 cm.moveColumn(index, lc);
48422 this.grid.fireEvent("columnmove", index, lc);
48424 cm.setLocked(index, true);
48428 var lc = cm.getLockedCount();
48429 if((lc-1) != index){
48430 cm.setLocked(index, false, true);
48431 cm.moveColumn(index, lc-1);
48432 this.grid.fireEvent("columnmove", index, lc-1);
48434 cm.setLocked(index, false);
48438 index = cm.getIndexById(item.id.substr(4));
48440 if(item.checked && cm.getColumnCount(true) <= 1){
48441 this.onDenyColumnHide();
48444 cm.setHidden(index, item.checked);
48450 beforeColMenuShow : function(){
48451 var cm = this.cm, colCount = cm.getColumnCount();
48452 this.colMenu.removeAll();
48453 for(var i = 0; i < colCount; i++){
48454 this.colMenu.add(new Roo.menu.CheckItem({
48455 id: "col-"+cm.getColumnId(i),
48456 text: cm.getColumnHeader(i),
48457 checked: !cm.isHidden(i),
48463 handleHdCtx : function(g, index, e){
48465 var hd = this.getHeaderCell(index);
48466 this.hdCtxIndex = index;
48467 var ms = this.hmenu.items, cm = this.cm;
48468 ms.get("asc").setDisabled(!cm.isSortable(index));
48469 ms.get("desc").setDisabled(!cm.isSortable(index));
48470 if(this.grid.enableColLock !== false){
48471 ms.get("lock").setDisabled(cm.isLocked(index));
48472 ms.get("unlock").setDisabled(!cm.isLocked(index));
48474 this.hmenu.show(hd, "tl-bl");
48477 handleHdOver : function(e){
48478 var hd = this.findHeaderCell(e.getTarget());
48479 if(hd && !this.headersDisabled){
48480 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48481 this.fly(hd).addClass("x-grid-hd-over");
48486 handleHdOut : function(e){
48487 var hd = this.findHeaderCell(e.getTarget());
48489 this.fly(hd).removeClass("x-grid-hd-over");
48493 handleSplitDblClick : function(e, t){
48494 var i = this.getCellIndex(t);
48495 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48496 this.autoSizeColumn(i, true);
48501 render : function(){
48504 var colCount = cm.getColumnCount();
48506 if(this.grid.monitorWindowResize === true){
48507 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48509 var header = this.renderHeaders();
48510 var body = this.templates.body.apply({rows:""});
48511 var html = this.templates.master.apply({
48514 lockedHeader: header[0],
48518 //this.updateColumns();
48520 this.grid.getGridEl().dom.innerHTML = html;
48522 this.initElements();
48524 // a kludge to fix the random scolling effect in webkit
48525 this.el.on("scroll", function() {
48526 this.el.dom.scrollTop=0; // hopefully not recursive..
48529 this.scroller.on("scroll", this.handleScroll, this);
48530 this.lockedBody.on("mousewheel", this.handleWheel, this);
48531 this.mainBody.on("mousewheel", this.handleWheel, this);
48533 this.mainHd.on("mouseover", this.handleHdOver, this);
48534 this.mainHd.on("mouseout", this.handleHdOut, this);
48535 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48536 {delegate: "."+this.splitClass});
48538 this.lockedHd.on("mouseover", this.handleHdOver, this);
48539 this.lockedHd.on("mouseout", this.handleHdOut, this);
48540 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48541 {delegate: "."+this.splitClass});
48543 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48544 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48547 this.updateSplitters();
48549 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48550 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48551 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48554 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48555 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48557 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48558 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48560 if(this.grid.enableColLock !== false){
48561 this.hmenu.add('-',
48562 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48563 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48566 if(this.grid.enableColumnHide !== false){
48568 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48569 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48570 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48572 this.hmenu.add('-',
48573 {id:"columns", text: this.columnsText, menu: this.colMenu}
48576 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48578 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48581 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48582 this.dd = new Roo.grid.GridDragZone(this.grid, {
48583 ddGroup : this.grid.ddGroup || 'GridDD'
48588 for(var i = 0; i < colCount; i++){
48589 if(cm.isHidden(i)){
48590 this.hideColumn(i);
48592 if(cm.config[i].align){
48593 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48594 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48598 this.updateHeaderSortState();
48600 this.beforeInitialResize();
48603 // two part rendering gives faster view to the user
48604 this.renderPhase2.defer(1, this);
48607 renderPhase2 : function(){
48608 // render the rows now
48610 if(this.grid.autoSizeColumns){
48611 this.autoSizeColumns();
48615 beforeInitialResize : function(){
48619 onColumnSplitterMoved : function(i, w){
48620 this.userResized = true;
48621 var cm = this.grid.colModel;
48622 cm.setColumnWidth(i, w, true);
48623 var cid = cm.getColumnId(i);
48624 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48625 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48626 this.updateSplitters();
48628 this.grid.fireEvent("columnresize", i, w);
48631 syncRowHeights : function(startIndex, endIndex){
48632 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48633 startIndex = startIndex || 0;
48634 var mrows = this.getBodyTable().rows;
48635 var lrows = this.getLockedTable().rows;
48636 var len = mrows.length-1;
48637 endIndex = Math.min(endIndex || len, len);
48638 for(var i = startIndex; i <= endIndex; i++){
48639 var m = mrows[i], l = lrows[i];
48640 var h = Math.max(m.offsetHeight, l.offsetHeight);
48641 m.style.height = l.style.height = h + "px";
48646 layout : function(initialRender, is2ndPass){
48648 var auto = g.autoHeight;
48649 var scrollOffset = 16;
48650 var c = g.getGridEl(), cm = this.cm,
48651 expandCol = g.autoExpandColumn,
48653 //c.beginMeasure();
48655 if(!c.dom.offsetWidth){ // display:none?
48657 this.lockedWrap.show();
48658 this.mainWrap.show();
48663 var hasLock = this.cm.isLocked(0);
48665 var tbh = this.headerPanel.getHeight();
48666 var bbh = this.footerPanel.getHeight();
48669 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48670 var newHeight = ch + c.getBorderWidth("tb");
48672 newHeight = Math.min(g.maxHeight, newHeight);
48674 c.setHeight(newHeight);
48678 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48681 var s = this.scroller;
48683 var csize = c.getSize(true);
48685 this.el.setSize(csize.width, csize.height);
48687 this.headerPanel.setWidth(csize.width);
48688 this.footerPanel.setWidth(csize.width);
48690 var hdHeight = this.mainHd.getHeight();
48691 var vw = csize.width;
48692 var vh = csize.height - (tbh + bbh);
48696 var bt = this.getBodyTable();
48697 var ltWidth = hasLock ?
48698 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48700 var scrollHeight = bt.offsetHeight;
48701 var scrollWidth = ltWidth + bt.offsetWidth;
48702 var vscroll = false, hscroll = false;
48704 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48706 var lw = this.lockedWrap, mw = this.mainWrap;
48707 var lb = this.lockedBody, mb = this.mainBody;
48709 setTimeout(function(){
48710 var t = s.dom.offsetTop;
48711 var w = s.dom.clientWidth,
48712 h = s.dom.clientHeight;
48715 lw.setSize(ltWidth, h);
48717 mw.setLeftTop(ltWidth, t);
48718 mw.setSize(w-ltWidth, h);
48720 lb.setHeight(h-hdHeight);
48721 mb.setHeight(h-hdHeight);
48723 if(is2ndPass !== true && !gv.userResized && expandCol){
48724 // high speed resize without full column calculation
48726 var ci = cm.getIndexById(expandCol);
48728 ci = cm.findColumnIndex(expandCol);
48730 ci = Math.max(0, ci); // make sure it's got at least the first col.
48731 var expandId = cm.getColumnId(ci);
48732 var tw = cm.getTotalWidth(false);
48733 var currentWidth = cm.getColumnWidth(ci);
48734 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48735 if(currentWidth != cw){
48736 cm.setColumnWidth(ci, cw, true);
48737 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48738 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48739 gv.updateSplitters();
48740 gv.layout(false, true);
48752 onWindowResize : function(){
48753 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48759 appendFooter : function(parentEl){
48763 sortAscText : "Sort Ascending",
48764 sortDescText : "Sort Descending",
48765 lockText : "Lock Column",
48766 unlockText : "Unlock Column",
48767 columnsText : "Columns"
48771 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
48772 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
48773 this.proxy.el.addClass('x-grid3-col-dd');
48776 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48777 handleMouseDown : function(e){
48781 callHandleMouseDown : function(e){
48782 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48787 * Ext JS Library 1.1.1
48788 * Copyright(c) 2006-2007, Ext JS, LLC.
48790 * Originally Released Under LGPL - original licence link has changed is not relivant.
48793 * <script type="text/javascript">
48797 // This is a support class used internally by the Grid components
48798 Roo.grid.SplitDragZone = function(grid, hd, hd2){
48800 this.view = grid.getView();
48801 this.proxy = this.view.resizeProxy;
48802 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48803 "gridSplitters" + this.grid.getGridEl().id, {
48804 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48806 this.setHandleElId(Roo.id(hd));
48807 this.setOuterHandleElId(Roo.id(hd2));
48808 this.scroll = false;
48810 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48811 fly: Roo.Element.fly,
48813 b4StartDrag : function(x, y){
48814 this.view.headersDisabled = true;
48815 this.proxy.setHeight(this.view.mainWrap.getHeight());
48816 var w = this.cm.getColumnWidth(this.cellIndex);
48817 var minw = Math.max(w-this.grid.minColumnWidth, 0);
48818 this.resetConstraints();
48819 this.setXConstraint(minw, 1000);
48820 this.setYConstraint(0, 0);
48821 this.minX = x - minw;
48822 this.maxX = x + 1000;
48824 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48828 handleMouseDown : function(e){
48829 ev = Roo.EventObject.setEvent(e);
48830 var t = this.fly(ev.getTarget());
48831 if(t.hasClass("x-grid-split")){
48832 this.cellIndex = this.view.getCellIndex(t.dom);
48833 this.split = t.dom;
48834 this.cm = this.grid.colModel;
48835 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48836 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48841 endDrag : function(e){
48842 this.view.headersDisabled = false;
48843 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48844 var diff = endX - this.startPos;
48845 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
48848 autoOffset : function(){
48849 this.setDelta(0,0);
48853 * Ext JS Library 1.1.1
48854 * Copyright(c) 2006-2007, Ext JS, LLC.
48856 * Originally Released Under LGPL - original licence link has changed is not relivant.
48859 * <script type="text/javascript">
48863 // This is a support class used internally by the Grid components
48864 Roo.grid.GridDragZone = function(grid, config){
48865 this.view = grid.getView();
48866 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
48867 if(this.view.lockedBody){
48868 this.setHandleElId(Roo.id(this.view.mainBody.dom));
48869 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48871 this.scroll = false;
48873 this.ddel = document.createElement('div');
48874 this.ddel.className = 'x-grid-dd-wrap';
48877 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48878 ddGroup : "GridDD",
48880 getDragData : function(e){
48881 var t = Roo.lib.Event.getTarget(e);
48882 var rowIndex = this.view.findRowIndex(t);
48883 if(rowIndex !== false){
48884 var sm = this.grid.selModel;
48885 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48886 // sm.mouseDown(e, t);
48888 if (e.hasModifier()){
48889 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48891 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
48896 onInitDrag : function(e){
48897 var data = this.dragData;
48898 this.ddel.innerHTML = this.grid.getDragDropText();
48899 this.proxy.update(this.ddel);
48900 // fire start drag?
48903 afterRepair : function(){
48904 this.dragging = false;
48907 getRepairXY : function(e, data){
48911 onEndDrag : function(data, e){
48915 onValidDrop : function(dd, e, id){
48920 beforeInvalidDrop : function(e, id){
48925 * Ext JS Library 1.1.1
48926 * Copyright(c) 2006-2007, Ext JS, LLC.
48928 * Originally Released Under LGPL - original licence link has changed is not relivant.
48931 * <script type="text/javascript">
48936 * @class Roo.grid.ColumnModel
48937 * @extends Roo.util.Observable
48938 * This is the default implementation of a ColumnModel used by the Grid. It defines
48939 * the columns in the grid.
48942 var colModel = new Roo.grid.ColumnModel([
48943 {header: "Ticker", width: 60, sortable: true, locked: true},
48944 {header: "Company Name", width: 150, sortable: true},
48945 {header: "Market Cap.", width: 100, sortable: true},
48946 {header: "$ Sales", width: 100, sortable: true, renderer: money},
48947 {header: "Employees", width: 100, sortable: true, resizable: false}
48952 * The config options listed for this class are options which may appear in each
48953 * individual column definition.
48954 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48956 * @param {Object} config An Array of column config objects. See this class's
48957 * config objects for details.
48959 Roo.grid.ColumnModel = function(config){
48961 * The config passed into the constructor
48963 this.config = config;
48966 // if no id, create one
48967 // if the column does not have a dataIndex mapping,
48968 // map it to the order it is in the config
48969 for(var i = 0, len = config.length; i < len; i++){
48971 if(typeof c.dataIndex == "undefined"){
48974 if(typeof c.renderer == "string"){
48975 c.renderer = Roo.util.Format[c.renderer];
48977 if(typeof c.id == "undefined"){
48980 if(c.editor && c.editor.xtype){
48981 c.editor = Roo.factory(c.editor, Roo.grid);
48983 if(c.editor && c.editor.isFormField){
48984 c.editor = new Roo.grid.GridEditor(c.editor);
48986 this.lookup[c.id] = c;
48990 * The width of columns which have no width specified (defaults to 100)
48993 this.defaultWidth = 100;
48996 * Default sortable of columns which have no sortable specified (defaults to false)
48999 this.defaultSortable = false;
49003 * @event widthchange
49004 * Fires when the width of a column changes.
49005 * @param {ColumnModel} this
49006 * @param {Number} columnIndex The column index
49007 * @param {Number} newWidth The new width
49009 "widthchange": true,
49011 * @event headerchange
49012 * Fires when the text of a header changes.
49013 * @param {ColumnModel} this
49014 * @param {Number} columnIndex The column index
49015 * @param {Number} newText The new header text
49017 "headerchange": true,
49019 * @event hiddenchange
49020 * Fires when a column is hidden or "unhidden".
49021 * @param {ColumnModel} this
49022 * @param {Number} columnIndex The column index
49023 * @param {Boolean} hidden true if hidden, false otherwise
49025 "hiddenchange": true,
49027 * @event columnmoved
49028 * Fires when a column is moved.
49029 * @param {ColumnModel} this
49030 * @param {Number} oldIndex
49031 * @param {Number} newIndex
49033 "columnmoved" : true,
49035 * @event columlockchange
49036 * Fires when a column's locked state is changed
49037 * @param {ColumnModel} this
49038 * @param {Number} colIndex
49039 * @param {Boolean} locked true if locked
49041 "columnlockchange" : true
49043 Roo.grid.ColumnModel.superclass.constructor.call(this);
49045 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
49047 * @cfg {String} header The header text to display in the Grid view.
49050 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
49051 * {@link Roo.data.Record} definition from which to draw the column's value. If not
49052 * specified, the column's index is used as an index into the Record's data Array.
49055 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
49056 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
49059 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
49060 * Defaults to the value of the {@link #defaultSortable} property.
49061 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
49064 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
49067 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
49070 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
49073 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
49076 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
49077 * given the cell's data value. See {@link #setRenderer}. If not specified, the
49078 * default renderer uses the raw data value.
49081 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
49084 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
49088 * Returns the id of the column at the specified index.
49089 * @param {Number} index The column index
49090 * @return {String} the id
49092 getColumnId : function(index){
49093 return this.config[index].id;
49097 * Returns the column for a specified id.
49098 * @param {String} id The column id
49099 * @return {Object} the column
49101 getColumnById : function(id){
49102 return this.lookup[id];
49107 * Returns the column for a specified dataIndex.
49108 * @param {String} dataIndex The column dataIndex
49109 * @return {Object|Boolean} the column or false if not found
49111 getColumnByDataIndex: function(dataIndex){
49112 var index = this.findColumnIndex(dataIndex);
49113 return index > -1 ? this.config[index] : false;
49117 * Returns the index for a specified column id.
49118 * @param {String} id The column id
49119 * @return {Number} the index, or -1 if not found
49121 getIndexById : function(id){
49122 for(var i = 0, len = this.config.length; i < len; i++){
49123 if(this.config[i].id == id){
49131 * Returns the index for a specified column dataIndex.
49132 * @param {String} dataIndex The column dataIndex
49133 * @return {Number} the index, or -1 if not found
49136 findColumnIndex : function(dataIndex){
49137 for(var i = 0, len = this.config.length; i < len; i++){
49138 if(this.config[i].dataIndex == dataIndex){
49146 moveColumn : function(oldIndex, newIndex){
49147 var c = this.config[oldIndex];
49148 this.config.splice(oldIndex, 1);
49149 this.config.splice(newIndex, 0, c);
49150 this.dataMap = null;
49151 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49154 isLocked : function(colIndex){
49155 return this.config[colIndex].locked === true;
49158 setLocked : function(colIndex, value, suppressEvent){
49159 if(this.isLocked(colIndex) == value){
49162 this.config[colIndex].locked = value;
49163 if(!suppressEvent){
49164 this.fireEvent("columnlockchange", this, colIndex, value);
49168 getTotalLockedWidth : function(){
49169 var totalWidth = 0;
49170 for(var i = 0; i < this.config.length; i++){
49171 if(this.isLocked(i) && !this.isHidden(i)){
49172 this.totalWidth += this.getColumnWidth(i);
49178 getLockedCount : function(){
49179 for(var i = 0, len = this.config.length; i < len; i++){
49180 if(!this.isLocked(i)){
49187 * Returns the number of columns.
49190 getColumnCount : function(visibleOnly){
49191 if(visibleOnly === true){
49193 for(var i = 0, len = this.config.length; i < len; i++){
49194 if(!this.isHidden(i)){
49200 return this.config.length;
49204 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49205 * @param {Function} fn
49206 * @param {Object} scope (optional)
49207 * @return {Array} result
49209 getColumnsBy : function(fn, scope){
49211 for(var i = 0, len = this.config.length; i < len; i++){
49212 var c = this.config[i];
49213 if(fn.call(scope||this, c, i) === true){
49221 * Returns true if the specified column is sortable.
49222 * @param {Number} col The column index
49223 * @return {Boolean}
49225 isSortable : function(col){
49226 if(typeof this.config[col].sortable == "undefined"){
49227 return this.defaultSortable;
49229 return this.config[col].sortable;
49233 * Returns the rendering (formatting) function defined for the column.
49234 * @param {Number} col The column index.
49235 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49237 getRenderer : function(col){
49238 if(!this.config[col].renderer){
49239 return Roo.grid.ColumnModel.defaultRenderer;
49241 return this.config[col].renderer;
49245 * Sets the rendering (formatting) function for a column.
49246 * @param {Number} col The column index
49247 * @param {Function} fn The function to use to process the cell's raw data
49248 * to return HTML markup for the grid view. The render function is called with
49249 * the following parameters:<ul>
49250 * <li>Data value.</li>
49251 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49252 * <li>css A CSS style string to apply to the table cell.</li>
49253 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49254 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49255 * <li>Row index</li>
49256 * <li>Column index</li>
49257 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49259 setRenderer : function(col, fn){
49260 this.config[col].renderer = fn;
49264 * Returns the width for the specified column.
49265 * @param {Number} col The column index
49268 getColumnWidth : function(col){
49269 return this.config[col].width * 1 || this.defaultWidth;
49273 * Sets the width for a column.
49274 * @param {Number} col The column index
49275 * @param {Number} width The new width
49277 setColumnWidth : function(col, width, suppressEvent){
49278 this.config[col].width = width;
49279 this.totalWidth = null;
49280 if(!suppressEvent){
49281 this.fireEvent("widthchange", this, col, width);
49286 * Returns the total width of all columns.
49287 * @param {Boolean} includeHidden True to include hidden column widths
49290 getTotalWidth : function(includeHidden){
49291 if(!this.totalWidth){
49292 this.totalWidth = 0;
49293 for(var i = 0, len = this.config.length; i < len; i++){
49294 if(includeHidden || !this.isHidden(i)){
49295 this.totalWidth += this.getColumnWidth(i);
49299 return this.totalWidth;
49303 * Returns the header for the specified column.
49304 * @param {Number} col The column index
49307 getColumnHeader : function(col){
49308 return this.config[col].header;
49312 * Sets the header for a column.
49313 * @param {Number} col The column index
49314 * @param {String} header The new header
49316 setColumnHeader : function(col, header){
49317 this.config[col].header = header;
49318 this.fireEvent("headerchange", this, col, header);
49322 * Returns the tooltip for the specified column.
49323 * @param {Number} col The column index
49326 getColumnTooltip : function(col){
49327 return this.config[col].tooltip;
49330 * Sets the tooltip for a column.
49331 * @param {Number} col The column index
49332 * @param {String} tooltip The new tooltip
49334 setColumnTooltip : function(col, tooltip){
49335 this.config[col].tooltip = tooltip;
49339 * Returns the dataIndex for the specified column.
49340 * @param {Number} col The column index
49343 getDataIndex : function(col){
49344 return this.config[col].dataIndex;
49348 * Sets the dataIndex for a column.
49349 * @param {Number} col The column index
49350 * @param {Number} dataIndex The new dataIndex
49352 setDataIndex : function(col, dataIndex){
49353 this.config[col].dataIndex = dataIndex;
49359 * Returns true if the cell is editable.
49360 * @param {Number} colIndex The column index
49361 * @param {Number} rowIndex The row index
49362 * @return {Boolean}
49364 isCellEditable : function(colIndex, rowIndex){
49365 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49369 * Returns the editor defined for the cell/column.
49370 * return false or null to disable editing.
49371 * @param {Number} colIndex The column index
49372 * @param {Number} rowIndex The row index
49375 getCellEditor : function(colIndex, rowIndex){
49376 return this.config[colIndex].editor;
49380 * Sets if a column is editable.
49381 * @param {Number} col The column index
49382 * @param {Boolean} editable True if the column is editable
49384 setEditable : function(col, editable){
49385 this.config[col].editable = editable;
49390 * Returns true if the column is hidden.
49391 * @param {Number} colIndex The column index
49392 * @return {Boolean}
49394 isHidden : function(colIndex){
49395 return this.config[colIndex].hidden;
49400 * Returns true if the column width cannot be changed
49402 isFixed : function(colIndex){
49403 return this.config[colIndex].fixed;
49407 * Returns true if the column can be resized
49408 * @return {Boolean}
49410 isResizable : function(colIndex){
49411 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49414 * Sets if a column is hidden.
49415 * @param {Number} colIndex The column index
49416 * @param {Boolean} hidden True if the column is hidden
49418 setHidden : function(colIndex, hidden){
49419 this.config[colIndex].hidden = hidden;
49420 this.totalWidth = null;
49421 this.fireEvent("hiddenchange", this, colIndex, hidden);
49425 * Sets the editor for a column.
49426 * @param {Number} col The column index
49427 * @param {Object} editor The editor object
49429 setEditor : function(col, editor){
49430 this.config[col].editor = editor;
49434 Roo.grid.ColumnModel.defaultRenderer = function(value){
49435 if(typeof value == "string" && value.length < 1){
49441 // Alias for backwards compatibility
49442 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49445 * Ext JS Library 1.1.1
49446 * Copyright(c) 2006-2007, Ext JS, LLC.
49448 * Originally Released Under LGPL - original licence link has changed is not relivant.
49451 * <script type="text/javascript">
49455 * @class Roo.grid.AbstractSelectionModel
49456 * @extends Roo.util.Observable
49457 * Abstract base class for grid SelectionModels. It provides the interface that should be
49458 * implemented by descendant classes. This class should not be directly instantiated.
49461 Roo.grid.AbstractSelectionModel = function(){
49462 this.locked = false;
49463 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49466 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49467 /** @ignore Called by the grid automatically. Do not call directly. */
49468 init : function(grid){
49474 * Locks the selections.
49477 this.locked = true;
49481 * Unlocks the selections.
49483 unlock : function(){
49484 this.locked = false;
49488 * Returns true if the selections are locked.
49489 * @return {Boolean}
49491 isLocked : function(){
49492 return this.locked;
49496 * Ext JS Library 1.1.1
49497 * Copyright(c) 2006-2007, Ext JS, LLC.
49499 * Originally Released Under LGPL - original licence link has changed is not relivant.
49502 * <script type="text/javascript">
49505 * @extends Roo.grid.AbstractSelectionModel
49506 * @class Roo.grid.RowSelectionModel
49507 * The default SelectionModel used by {@link Roo.grid.Grid}.
49508 * It supports multiple selections and keyboard selection/navigation.
49510 * @param {Object} config
49512 Roo.grid.RowSelectionModel = function(config){
49513 Roo.apply(this, config);
49514 this.selections = new Roo.util.MixedCollection(false, function(o){
49519 this.lastActive = false;
49523 * @event selectionchange
49524 * Fires when the selection changes
49525 * @param {SelectionModel} this
49527 "selectionchange" : true,
49529 * @event afterselectionchange
49530 * Fires after the selection changes (eg. by key press or clicking)
49531 * @param {SelectionModel} this
49533 "afterselectionchange" : true,
49535 * @event beforerowselect
49536 * Fires when a row is selected being selected, return false to cancel.
49537 * @param {SelectionModel} this
49538 * @param {Number} rowIndex The selected index
49539 * @param {Boolean} keepExisting False if other selections will be cleared
49541 "beforerowselect" : true,
49544 * Fires when a row is selected.
49545 * @param {SelectionModel} this
49546 * @param {Number} rowIndex The selected index
49547 * @param {Roo.data.Record} r The record
49549 "rowselect" : true,
49551 * @event rowdeselect
49552 * Fires when a row is deselected.
49553 * @param {SelectionModel} this
49554 * @param {Number} rowIndex The selected index
49556 "rowdeselect" : true
49558 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49559 this.locked = false;
49562 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49564 * @cfg {Boolean} singleSelect
49565 * True to allow selection of only one row at a time (defaults to false)
49567 singleSelect : false,
49570 initEvents : function(){
49572 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49573 this.grid.on("mousedown", this.handleMouseDown, this);
49574 }else{ // allow click to work like normal
49575 this.grid.on("rowclick", this.handleDragableRowClick, this);
49578 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49579 "up" : function(e){
49581 this.selectPrevious(e.shiftKey);
49582 }else if(this.last !== false && this.lastActive !== false){
49583 var last = this.last;
49584 this.selectRange(this.last, this.lastActive-1);
49585 this.grid.getView().focusRow(this.lastActive);
49586 if(last !== false){
49590 this.selectFirstRow();
49592 this.fireEvent("afterselectionchange", this);
49594 "down" : function(e){
49596 this.selectNext(e.shiftKey);
49597 }else if(this.last !== false && this.lastActive !== false){
49598 var last = this.last;
49599 this.selectRange(this.last, this.lastActive+1);
49600 this.grid.getView().focusRow(this.lastActive);
49601 if(last !== false){
49605 this.selectFirstRow();
49607 this.fireEvent("afterselectionchange", this);
49612 var view = this.grid.view;
49613 view.on("refresh", this.onRefresh, this);
49614 view.on("rowupdated", this.onRowUpdated, this);
49615 view.on("rowremoved", this.onRemove, this);
49619 onRefresh : function(){
49620 var ds = this.grid.dataSource, i, v = this.grid.view;
49621 var s = this.selections;
49622 s.each(function(r){
49623 if((i = ds.indexOfId(r.id)) != -1){
49632 onRemove : function(v, index, r){
49633 this.selections.remove(r);
49637 onRowUpdated : function(v, index, r){
49638 if(this.isSelected(r)){
49639 v.onRowSelect(index);
49645 * @param {Array} records The records to select
49646 * @param {Boolean} keepExisting (optional) True to keep existing selections
49648 selectRecords : function(records, keepExisting){
49650 this.clearSelections();
49652 var ds = this.grid.dataSource;
49653 for(var i = 0, len = records.length; i < len; i++){
49654 this.selectRow(ds.indexOf(records[i]), true);
49659 * Gets the number of selected rows.
49662 getCount : function(){
49663 return this.selections.length;
49667 * Selects the first row in the grid.
49669 selectFirstRow : function(){
49674 * Select the last row.
49675 * @param {Boolean} keepExisting (optional) True to keep existing selections
49677 selectLastRow : function(keepExisting){
49678 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49682 * Selects the row immediately following the last selected row.
49683 * @param {Boolean} keepExisting (optional) True to keep existing selections
49685 selectNext : function(keepExisting){
49686 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49687 this.selectRow(this.last+1, keepExisting);
49688 this.grid.getView().focusRow(this.last);
49693 * Selects the row that precedes the last selected row.
49694 * @param {Boolean} keepExisting (optional) True to keep existing selections
49696 selectPrevious : function(keepExisting){
49698 this.selectRow(this.last-1, keepExisting);
49699 this.grid.getView().focusRow(this.last);
49704 * Returns the selected records
49705 * @return {Array} Array of selected records
49707 getSelections : function(){
49708 return [].concat(this.selections.items);
49712 * Returns the first selected record.
49715 getSelected : function(){
49716 return this.selections.itemAt(0);
49721 * Clears all selections.
49723 clearSelections : function(fast){
49724 if(this.locked) return;
49726 var ds = this.grid.dataSource;
49727 var s = this.selections;
49728 s.each(function(r){
49729 this.deselectRow(ds.indexOfId(r.id));
49733 this.selections.clear();
49740 * Selects all rows.
49742 selectAll : function(){
49743 if(this.locked) return;
49744 this.selections.clear();
49745 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49746 this.selectRow(i, true);
49751 * Returns True if there is a selection.
49752 * @return {Boolean}
49754 hasSelection : function(){
49755 return this.selections.length > 0;
49759 * Returns True if the specified row is selected.
49760 * @param {Number/Record} record The record or index of the record to check
49761 * @return {Boolean}
49763 isSelected : function(index){
49764 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
49765 return (r && this.selections.key(r.id) ? true : false);
49769 * Returns True if the specified record id is selected.
49770 * @param {String} id The id of record to check
49771 * @return {Boolean}
49773 isIdSelected : function(id){
49774 return (this.selections.key(id) ? true : false);
49778 handleMouseDown : function(e, t){
49779 var view = this.grid.getView(), rowIndex;
49780 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
49783 if(e.shiftKey && this.last !== false){
49784 var last = this.last;
49785 this.selectRange(last, rowIndex, e.ctrlKey);
49786 this.last = last; // reset the last
49787 view.focusRow(rowIndex);
49789 var isSelected = this.isSelected(rowIndex);
49790 if(e.button !== 0 && isSelected){
49791 view.focusRow(rowIndex);
49792 }else if(e.ctrlKey && isSelected){
49793 this.deselectRow(rowIndex);
49794 }else if(!isSelected){
49795 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
49796 view.focusRow(rowIndex);
49799 this.fireEvent("afterselectionchange", this);
49802 handleDragableRowClick : function(grid, rowIndex, e)
49804 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49805 this.selectRow(rowIndex, false);
49806 grid.view.focusRow(rowIndex);
49807 this.fireEvent("afterselectionchange", this);
49812 * Selects multiple rows.
49813 * @param {Array} rows Array of the indexes of the row to select
49814 * @param {Boolean} keepExisting (optional) True to keep existing selections
49816 selectRows : function(rows, keepExisting){
49818 this.clearSelections();
49820 for(var i = 0, len = rows.length; i < len; i++){
49821 this.selectRow(rows[i], true);
49826 * Selects a range of rows. All rows in between startRow and endRow are also selected.
49827 * @param {Number} startRow The index of the first row in the range
49828 * @param {Number} endRow The index of the last row in the range
49829 * @param {Boolean} keepExisting (optional) True to retain existing selections
49831 selectRange : function(startRow, endRow, keepExisting){
49832 if(this.locked) return;
49834 this.clearSelections();
49836 if(startRow <= endRow){
49837 for(var i = startRow; i <= endRow; i++){
49838 this.selectRow(i, true);
49841 for(var i = startRow; i >= endRow; i--){
49842 this.selectRow(i, true);
49848 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49849 * @param {Number} startRow The index of the first row in the range
49850 * @param {Number} endRow The index of the last row in the range
49852 deselectRange : function(startRow, endRow, preventViewNotify){
49853 if(this.locked) return;
49854 for(var i = startRow; i <= endRow; i++){
49855 this.deselectRow(i, preventViewNotify);
49861 * @param {Number} row The index of the row to select
49862 * @param {Boolean} keepExisting (optional) True to keep existing selections
49864 selectRow : function(index, keepExisting, preventViewNotify){
49865 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
49866 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
49867 if(!keepExisting || this.singleSelect){
49868 this.clearSelections();
49870 var r = this.grid.dataSource.getAt(index);
49871 this.selections.add(r);
49872 this.last = this.lastActive = index;
49873 if(!preventViewNotify){
49874 this.grid.getView().onRowSelect(index);
49876 this.fireEvent("rowselect", this, index, r);
49877 this.fireEvent("selectionchange", this);
49883 * @param {Number} row The index of the row to deselect
49885 deselectRow : function(index, preventViewNotify){
49886 if(this.locked) return;
49887 if(this.last == index){
49890 if(this.lastActive == index){
49891 this.lastActive = false;
49893 var r = this.grid.dataSource.getAt(index);
49894 this.selections.remove(r);
49895 if(!preventViewNotify){
49896 this.grid.getView().onRowDeselect(index);
49898 this.fireEvent("rowdeselect", this, index);
49899 this.fireEvent("selectionchange", this);
49903 restoreLast : function(){
49905 this.last = this._last;
49910 acceptsNav : function(row, col, cm){
49911 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49915 onEditorKey : function(field, e){
49916 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49921 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49923 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49925 }else if(k == e.ENTER && !e.ctrlKey){
49929 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49931 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49933 }else if(k == e.ESC){
49937 g.startEditing(newCell[0], newCell[1]);
49942 * Ext JS Library 1.1.1
49943 * Copyright(c) 2006-2007, Ext JS, LLC.
49945 * Originally Released Under LGPL - original licence link has changed is not relivant.
49948 * <script type="text/javascript">
49951 * @class Roo.grid.CellSelectionModel
49952 * @extends Roo.grid.AbstractSelectionModel
49953 * This class provides the basic implementation for cell selection in a grid.
49955 * @param {Object} config The object containing the configuration of this model.
49957 Roo.grid.CellSelectionModel = function(config){
49958 Roo.apply(this, config);
49960 this.selection = null;
49964 * @event beforerowselect
49965 * Fires before a cell is selected.
49966 * @param {SelectionModel} this
49967 * @param {Number} rowIndex The selected row index
49968 * @param {Number} colIndex The selected cell index
49970 "beforecellselect" : true,
49972 * @event cellselect
49973 * Fires when a cell is selected.
49974 * @param {SelectionModel} this
49975 * @param {Number} rowIndex The selected row index
49976 * @param {Number} colIndex The selected cell index
49978 "cellselect" : true,
49980 * @event selectionchange
49981 * Fires when the active selection changes.
49982 * @param {SelectionModel} this
49983 * @param {Object} selection null for no selection or an object (o) with two properties
49985 <li>o.record: the record object for the row the selection is in</li>
49986 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49989 "selectionchange" : true
49991 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49994 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
49997 initEvents : function(){
49998 this.grid.on("mousedown", this.handleMouseDown, this);
49999 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
50000 var view = this.grid.view;
50001 view.on("refresh", this.onViewChange, this);
50002 view.on("rowupdated", this.onRowUpdated, this);
50003 view.on("beforerowremoved", this.clearSelections, this);
50004 view.on("beforerowsinserted", this.clearSelections, this);
50005 if(this.grid.isEditor){
50006 this.grid.on("beforeedit", this.beforeEdit, this);
50011 beforeEdit : function(e){
50012 this.select(e.row, e.column, false, true, e.record);
50016 onRowUpdated : function(v, index, r){
50017 if(this.selection && this.selection.record == r){
50018 v.onCellSelect(index, this.selection.cell[1]);
50023 onViewChange : function(){
50024 this.clearSelections(true);
50028 * Returns the currently selected cell,.
50029 * @return {Array} The selected cell (row, column) or null if none selected.
50031 getSelectedCell : function(){
50032 return this.selection ? this.selection.cell : null;
50036 * Clears all selections.
50037 * @param {Boolean} true to prevent the gridview from being notified about the change.
50039 clearSelections : function(preventNotify){
50040 var s = this.selection;
50042 if(preventNotify !== true){
50043 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
50045 this.selection = null;
50046 this.fireEvent("selectionchange", this, null);
50051 * Returns true if there is a selection.
50052 * @return {Boolean}
50054 hasSelection : function(){
50055 return this.selection ? true : false;
50059 handleMouseDown : function(e, t){
50060 var v = this.grid.getView();
50061 if(this.isLocked()){
50064 var row = v.findRowIndex(t);
50065 var cell = v.findCellIndex(t);
50066 if(row !== false && cell !== false){
50067 this.select(row, cell);
50073 * @param {Number} rowIndex
50074 * @param {Number} collIndex
50076 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
50077 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
50078 this.clearSelections();
50079 r = r || this.grid.dataSource.getAt(rowIndex);
50082 cell : [rowIndex, colIndex]
50084 if(!preventViewNotify){
50085 var v = this.grid.getView();
50086 v.onCellSelect(rowIndex, colIndex);
50087 if(preventFocus !== true){
50088 v.focusCell(rowIndex, colIndex);
50091 this.fireEvent("cellselect", this, rowIndex, colIndex);
50092 this.fireEvent("selectionchange", this, this.selection);
50097 isSelectable : function(rowIndex, colIndex, cm){
50098 return !cm.isHidden(colIndex);
50102 handleKeyDown : function(e){
50103 Roo.log('Cell Sel Model handleKeyDown');
50104 if(!e.isNavKeyPress()){
50107 var g = this.grid, s = this.selection;
50110 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50112 this.select(cell[0], cell[1]);
50117 var walk = function(row, col, step){
50118 return g.walkCells(row, col, step, sm.isSelectable, sm);
50120 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50125 // handled by onEditorKey
50126 if (g.isEditor && g.editing) {
50130 newCell = walk(r, c-1, -1);
50132 newCell = walk(r, c+1, 1);
50136 newCell = walk(r+1, c, 1);
50139 newCell = walk(r-1, c, -1);
50142 newCell = walk(r, c+1, 1);
50145 newCell = walk(r, c-1, -1);
50148 if(g.isEditor && !g.editing){
50149 g.startEditing(r, c);
50156 this.select(newCell[0], newCell[1]);
50161 acceptsNav : function(row, col, cm){
50162 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50165 onEditorKey : function(field, e){
50167 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50168 ///Roo.log('onEditorKey' + k);
50172 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50174 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50177 }else if(k == e.ENTER && !e.ctrlKey){
50180 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50181 }else if(k == e.ESC){
50187 //Roo.log('next cell after edit');
50188 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50193 * Ext JS Library 1.1.1
50194 * Copyright(c) 2006-2007, Ext JS, LLC.
50196 * Originally Released Under LGPL - original licence link has changed is not relivant.
50199 * <script type="text/javascript">
50203 * @class Roo.grid.EditorGrid
50204 * @extends Roo.grid.Grid
50205 * Class for creating and editable grid.
50206 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50207 * The container MUST have some type of size defined for the grid to fill. The container will be
50208 * automatically set to position relative if it isn't already.
50209 * @param {Object} dataSource The data model to bind to
50210 * @param {Object} colModel The column model with info about this grid's columns
50212 Roo.grid.EditorGrid = function(container, config){
50213 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50214 this.getGridEl().addClass("xedit-grid");
50216 if(!this.selModel){
50217 this.selModel = new Roo.grid.CellSelectionModel();
50220 this.activeEditor = null;
50224 * @event beforeedit
50225 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50226 * <ul style="padding:5px;padding-left:16px;">
50227 * <li>grid - This grid</li>
50228 * <li>record - The record being edited</li>
50229 * <li>field - The field name being edited</li>
50230 * <li>value - The value for the field being edited.</li>
50231 * <li>row - The grid row index</li>
50232 * <li>column - The grid column index</li>
50233 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50235 * @param {Object} e An edit event (see above for description)
50237 "beforeedit" : true,
50240 * Fires after a cell is edited. <br />
50241 * <ul style="padding:5px;padding-left:16px;">
50242 * <li>grid - This grid</li>
50243 * <li>record - The record being edited</li>
50244 * <li>field - The field name being edited</li>
50245 * <li>value - The value being set</li>
50246 * <li>originalValue - The original value for the field, before the edit.</li>
50247 * <li>row - The grid row index</li>
50248 * <li>column - The grid column index</li>
50250 * @param {Object} e An edit event (see above for description)
50252 "afteredit" : true,
50254 * @event validateedit
50255 * Fires after a cell is edited, but before the value is set in the record.
50256 * You can use this to modify the value being set in the field, Return false
50257 * to cancel the change. The edit event object has the following properties <br />
50258 * <ul style="padding:5px;padding-left:16px;">
50259 * <li>editor - This editor</li>
50260 * <li>grid - This grid</li>
50261 * <li>record - The record being edited</li>
50262 * <li>field - The field name being edited</li>
50263 * <li>value - The value being set</li>
50264 * <li>originalValue - The original value for the field, before the edit.</li>
50265 * <li>row - The grid row index</li>
50266 * <li>column - The grid column index</li>
50267 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50269 * @param {Object} e An edit event (see above for description)
50271 "validateedit" : true
50273 this.on("bodyscroll", this.stopEditing, this);
50274 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50277 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50279 * @cfg {Number} clicksToEdit
50280 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50287 trackMouseOver: false, // causes very odd FF errors
50289 onCellDblClick : function(g, row, col){
50290 this.startEditing(row, col);
50293 onEditComplete : function(ed, value, startValue){
50294 this.editing = false;
50295 this.activeEditor = null;
50296 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50298 var field = this.colModel.getDataIndex(ed.col);
50303 originalValue: startValue,
50310 if(String(value) !== String(startValue)){
50312 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50313 r.set(field, e.value);
50314 // if we are dealing with a combo box..
50315 // then we also set the 'name' colum to be the displayField
50316 if (ed.field.displayField && ed.field.name) {
50317 r.set(ed.field.name, ed.field.el.dom.value);
50320 delete e.cancel; //?? why!!!
50321 this.fireEvent("afteredit", e);
50324 this.fireEvent("afteredit", e); // always fire it!
50326 this.view.focusCell(ed.row, ed.col);
50330 * Starts editing the specified for the specified row/column
50331 * @param {Number} rowIndex
50332 * @param {Number} colIndex
50334 startEditing : function(row, col){
50335 this.stopEditing();
50336 if(this.colModel.isCellEditable(col, row)){
50337 this.view.ensureVisible(row, col, true);
50338 var r = this.dataSource.getAt(row);
50339 var field = this.colModel.getDataIndex(col);
50344 value: r.data[field],
50349 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50350 this.editing = true;
50351 var ed = this.colModel.getCellEditor(col, row);
50357 ed.render(ed.parentEl || document.body);
50360 (function(){ // complex but required for focus issues in safari, ie and opera
50364 ed.on("complete", this.onEditComplete, this, {single: true});
50365 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50366 this.activeEditor = ed;
50367 var v = r.data[field];
50368 ed.startEdit(this.view.getCell(row, col), v);
50369 // combo's with 'displayField and name set
50370 if (ed.field.displayField && ed.field.name) {
50371 ed.field.el.dom.value = r.data[ed.field.name];
50375 }).defer(50, this);
50381 * Stops any active editing
50383 stopEditing : function(){
50384 if(this.activeEditor){
50385 this.activeEditor.completeEdit();
50387 this.activeEditor = null;
50391 * Ext JS Library 1.1.1
50392 * Copyright(c) 2006-2007, Ext JS, LLC.
50394 * Originally Released Under LGPL - original licence link has changed is not relivant.
50397 * <script type="text/javascript">
50400 // private - not really -- you end up using it !
50401 // This is a support class used internally by the Grid components
50404 * @class Roo.grid.GridEditor
50405 * @extends Roo.Editor
50406 * Class for creating and editable grid elements.
50407 * @param {Object} config any settings (must include field)
50409 Roo.grid.GridEditor = function(field, config){
50410 if (!config && field.field) {
50412 field = Roo.factory(config.field, Roo.form);
50414 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50415 field.monitorTab = false;
50418 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50421 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50424 alignment: "tl-tl",
50427 cls: "x-small-editor x-grid-editor",
50432 * Ext JS Library 1.1.1
50433 * Copyright(c) 2006-2007, Ext JS, LLC.
50435 * Originally Released Under LGPL - original licence link has changed is not relivant.
50438 * <script type="text/javascript">
50443 Roo.grid.PropertyRecord = Roo.data.Record.create([
50444 {name:'name',type:'string'}, 'value'
50448 Roo.grid.PropertyStore = function(grid, source){
50450 this.store = new Roo.data.Store({
50451 recordType : Roo.grid.PropertyRecord
50453 this.store.on('update', this.onUpdate, this);
50455 this.setSource(source);
50457 Roo.grid.PropertyStore.superclass.constructor.call(this);
50462 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50463 setSource : function(o){
50465 this.store.removeAll();
50468 if(this.isEditableValue(o[k])){
50469 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50472 this.store.loadRecords({records: data}, {}, true);
50475 onUpdate : function(ds, record, type){
50476 if(type == Roo.data.Record.EDIT){
50477 var v = record.data['value'];
50478 var oldValue = record.modified['value'];
50479 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50480 this.source[record.id] = v;
50482 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50489 getProperty : function(row){
50490 return this.store.getAt(row);
50493 isEditableValue: function(val){
50494 if(val && val instanceof Date){
50496 }else if(typeof val == 'object' || typeof val == 'function'){
50502 setValue : function(prop, value){
50503 this.source[prop] = value;
50504 this.store.getById(prop).set('value', value);
50507 getSource : function(){
50508 return this.source;
50512 Roo.grid.PropertyColumnModel = function(grid, store){
50515 g.PropertyColumnModel.superclass.constructor.call(this, [
50516 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50517 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50519 this.store = store;
50520 this.bselect = Roo.DomHelper.append(document.body, {
50521 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50522 {tag: 'option', value: 'true', html: 'true'},
50523 {tag: 'option', value: 'false', html: 'false'}
50526 Roo.id(this.bselect);
50529 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50530 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50531 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50532 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50533 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50535 this.renderCellDelegate = this.renderCell.createDelegate(this);
50536 this.renderPropDelegate = this.renderProp.createDelegate(this);
50539 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50543 valueText : 'Value',
50545 dateFormat : 'm/j/Y',
50548 renderDate : function(dateVal){
50549 return dateVal.dateFormat(this.dateFormat);
50552 renderBool : function(bVal){
50553 return bVal ? 'true' : 'false';
50556 isCellEditable : function(colIndex, rowIndex){
50557 return colIndex == 1;
50560 getRenderer : function(col){
50562 this.renderCellDelegate : this.renderPropDelegate;
50565 renderProp : function(v){
50566 return this.getPropertyName(v);
50569 renderCell : function(val){
50571 if(val instanceof Date){
50572 rv = this.renderDate(val);
50573 }else if(typeof val == 'boolean'){
50574 rv = this.renderBool(val);
50576 return Roo.util.Format.htmlEncode(rv);
50579 getPropertyName : function(name){
50580 var pn = this.grid.propertyNames;
50581 return pn && pn[name] ? pn[name] : name;
50584 getCellEditor : function(colIndex, rowIndex){
50585 var p = this.store.getProperty(rowIndex);
50586 var n = p.data['name'], val = p.data['value'];
50588 if(typeof(this.grid.customEditors[n]) == 'string'){
50589 return this.editors[this.grid.customEditors[n]];
50591 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50592 return this.grid.customEditors[n];
50594 if(val instanceof Date){
50595 return this.editors['date'];
50596 }else if(typeof val == 'number'){
50597 return this.editors['number'];
50598 }else if(typeof val == 'boolean'){
50599 return this.editors['boolean'];
50601 return this.editors['string'];
50607 * @class Roo.grid.PropertyGrid
50608 * @extends Roo.grid.EditorGrid
50609 * This class represents the interface of a component based property grid control.
50610 * <br><br>Usage:<pre><code>
50611 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50619 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50620 * The container MUST have some type of size defined for the grid to fill. The container will be
50621 * automatically set to position relative if it isn't already.
50622 * @param {Object} config A config object that sets properties on this grid.
50624 Roo.grid.PropertyGrid = function(container, config){
50625 config = config || {};
50626 var store = new Roo.grid.PropertyStore(this);
50627 this.store = store;
50628 var cm = new Roo.grid.PropertyColumnModel(this, store);
50629 store.store.sort('name', 'ASC');
50630 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50633 enableColLock:false,
50634 enableColumnMove:false,
50636 trackMouseOver: false,
50639 this.getGridEl().addClass('x-props-grid');
50640 this.lastEditRow = null;
50641 this.on('columnresize', this.onColumnResize, this);
50644 * @event beforepropertychange
50645 * Fires before a property changes (return false to stop?)
50646 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50647 * @param {String} id Record Id
50648 * @param {String} newval New Value
50649 * @param {String} oldval Old Value
50651 "beforepropertychange": true,
50653 * @event propertychange
50654 * Fires after a property changes
50655 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50656 * @param {String} id Record Id
50657 * @param {String} newval New Value
50658 * @param {String} oldval Old Value
50660 "propertychange": true
50662 this.customEditors = this.customEditors || {};
50664 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50667 * @cfg {Object} customEditors map of colnames=> custom editors.
50668 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50669 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50670 * false disables editing of the field.
50674 * @cfg {Object} propertyNames map of property Names to their displayed value
50677 render : function(){
50678 Roo.grid.PropertyGrid.superclass.render.call(this);
50679 this.autoSize.defer(100, this);
50682 autoSize : function(){
50683 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50685 this.view.fitColumns();
50689 onColumnResize : function(){
50690 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50694 * Sets the data for the Grid
50695 * accepts a Key => Value object of all the elements avaiable.
50696 * @param {Object} data to appear in grid.
50698 setSource : function(source){
50699 this.store.setSource(source);
50703 * Gets all the data from the grid.
50704 * @return {Object} data data stored in grid
50706 getSource : function(){
50707 return this.store.getSource();
50711 * Ext JS Library 1.1.1
50712 * Copyright(c) 2006-2007, Ext JS, LLC.
50714 * Originally Released Under LGPL - original licence link has changed is not relivant.
50717 * <script type="text/javascript">
50721 * @class Roo.LoadMask
50722 * A simple utility class for generically masking elements while loading data. If the element being masked has
50723 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50724 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50725 * element's UpdateManager load indicator and will be destroyed after the initial load.
50727 * Create a new LoadMask
50728 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50729 * @param {Object} config The config object
50731 Roo.LoadMask = function(el, config){
50732 this.el = Roo.get(el);
50733 Roo.apply(this, config);
50735 this.store.on('beforeload', this.onBeforeLoad, this);
50736 this.store.on('load', this.onLoad, this);
50737 this.store.on('loadexception', this.onLoad, this);
50738 this.removeMask = false;
50740 var um = this.el.getUpdateManager();
50741 um.showLoadIndicator = false; // disable the default indicator
50742 um.on('beforeupdate', this.onBeforeLoad, this);
50743 um.on('update', this.onLoad, this);
50744 um.on('failure', this.onLoad, this);
50745 this.removeMask = true;
50749 Roo.LoadMask.prototype = {
50751 * @cfg {Boolean} removeMask
50752 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50753 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
50756 * @cfg {String} msg
50757 * The text to display in a centered loading message box (defaults to 'Loading...')
50759 msg : 'Loading...',
50761 * @cfg {String} msgCls
50762 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50764 msgCls : 'x-mask-loading',
50767 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50773 * Disables the mask to prevent it from being displayed
50775 disable : function(){
50776 this.disabled = true;
50780 * Enables the mask so that it can be displayed
50782 enable : function(){
50783 this.disabled = false;
50787 onLoad : function(){
50788 this.el.unmask(this.removeMask);
50792 onBeforeLoad : function(){
50793 if(!this.disabled){
50794 this.el.mask(this.msg, this.msgCls);
50799 destroy : function(){
50801 this.store.un('beforeload', this.onBeforeLoad, this);
50802 this.store.un('load', this.onLoad, this);
50803 this.store.un('loadexception', this.onLoad, this);
50805 var um = this.el.getUpdateManager();
50806 um.un('beforeupdate', this.onBeforeLoad, this);
50807 um.un('update', this.onLoad, this);
50808 um.un('failure', this.onLoad, this);
50813 * Ext JS Library 1.1.1
50814 * Copyright(c) 2006-2007, Ext JS, LLC.
50816 * Originally Released Under LGPL - original licence link has changed is not relivant.
50819 * <script type="text/javascript">
50821 Roo.XTemplate = function(){
50822 Roo.XTemplate.superclass.constructor.apply(this, arguments);
50825 s = ['<tpl>', s, '</tpl>'].join('');
50827 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50829 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
50830 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
50831 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
50835 while(m = s.match(re)){
50836 var m2 = m[0].match(nameRe);
50837 var m3 = m[0].match(ifRe);
50838 var m4 = m[0].match(execRe);
50839 var exp = null, fn = null, exec = null;
50840 var name = m2 && m2[1] ? m2[1] : '';
50842 exp = m3 && m3[1] ? m3[1] : null;
50844 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50848 exp = m4 && m4[1] ? m4[1] : null;
50850 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50855 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
50856 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
50857 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
50867 s = s.replace(m[0], '{xtpl'+ id + '}');
50870 for(var i = tpls.length-1; i >= 0; --i){
50871 this.compileTpl(tpls[i]);
50873 this.master = tpls[tpls.length-1];
50876 Roo.extend(Roo.XTemplate, Roo.Template, {
50878 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50880 applySubTemplate : function(id, values, parent){
50881 var t = this.tpls[id];
50882 if(t.test && !t.test.call(this, values, parent)){
50885 if(t.exec && t.exec.call(this, values, parent)){
50888 var vs = t.target ? t.target.call(this, values, parent) : values;
50889 parent = t.target ? values : parent;
50890 if(t.target && vs instanceof Array){
50892 for(var i = 0, len = vs.length; i < len; i++){
50893 buf[buf.length] = t.compiled.call(this, vs[i], parent);
50895 return buf.join('');
50897 return t.compiled.call(this, vs, parent);
50900 compileTpl : function(tpl){
50901 var fm = Roo.util.Format;
50902 var useF = this.disableFormats !== true;
50903 var sep = Roo.isGecko ? "+" : ",";
50904 var fn = function(m, name, format, args){
50905 if(name.substr(0, 4) == 'xtpl'){
50906 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
50909 if(name.indexOf('.') != -1){
50912 v = "values['" + name + "']";
50914 if(format && useF){
50915 args = args ? ',' + args : "";
50916 if(format.substr(0, 5) != "this."){
50917 format = "fm." + format + '(';
50919 format = 'this.call("'+ format.substr(5) + '", ';
50923 args= ''; format = "("+v+" === undefined ? '' : ";
50925 return "'"+ sep + format + v + args + ")"+sep+"'";
50928 // branched to use + in gecko and [].join() in others
50930 body = "tpl.compiled = function(values, parent){ return '" +
50931 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50934 body = ["tpl.compiled = function(values, parent){ return ['"];
50935 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50936 body.push("'].join('');};");
50937 body = body.join('');
50939 /** eval:var:zzzzzzz */
50944 applyTemplate : function(values){
50945 return this.master.compiled.call(this, values, {});
50949 apply : function(){
50950 return this.applyTemplate.apply(this, arguments);
50953 compile : function(){return this;}
50956 Roo.XTemplate.from = function(el){
50957 el = Roo.getDom(el);
50958 return new Roo.XTemplate(el.value || el.innerHTML);
50960 * Original code for Roojs - LGPL
50961 * <script type="text/javascript">
50965 * @class Roo.XComponent
50966 * A delayed Element creator...
50968 * Mypart.xyx = new Roo.XComponent({
50970 parent : 'Mypart.xyz', // empty == document.element.!!
50974 disabled : function() {}
50976 tree : function() { // return an tree of xtype declared components
50980 xtype : 'NestedLayoutPanel',
50985 * @extends Roo.util.Observable
50987 * @param cfg {Object} configuration of component
50990 Roo.XComponent = function(cfg) {
50991 Roo.apply(this, cfg);
50995 * Fires when this the componnt is built
50996 * @param {Roo.XComponent} c the component
51000 * @event buildcomplete
51001 * Fires on the top level element when all elements have been built
51002 * @param {Roo.XComponent} c the top level component.
51004 'buildcomplete' : true
51008 Roo.XComponent.register(this);
51009 this.modules = false;
51010 this.el = false; // where the layout goes..
51014 Roo.extend(Roo.XComponent, Roo.util.Observable, {
51017 * The created element (with Roo.factory())
51018 * @type {Roo.Layout}
51024 * for BC - use el in new code
51025 * @type {Roo.Layout}
51031 * for BC - use el in new code
51032 * @type {Roo.Layout}
51037 * @cfg {Function|boolean} disabled
51038 * If this module is disabled by some rule, return true from the funtion
51043 * @cfg {String} parent
51044 * Name of parent element which it get xtype added to..
51049 * @cfg {String} order
51050 * Used to set the order in which elements are created (usefull for multiple tabs)
51055 * @cfg {String} name
51056 * String to display while loading.
51060 * @cfg {Array} items
51061 * A single item array - the first element is the root of the tree..
51062 * It's done this way to stay compatible with the Xtype system...
51070 Roo.apply(Roo.XComponent, {
51073 * @property buildCompleted
51074 * True when the builder has completed building the interface.
51077 buildCompleted : false,
51080 * @property topModule
51081 * the upper most module - uses document.element as it's constructor.
51088 * @property modules
51089 * array of modules to be created by registration system.
51090 * @type Roo.XComponent
51097 * Register components to be built later.
51099 * This solves the following issues
51100 * - Building is not done on page load, but after an authentication process has occured.
51101 * - Interface elements are registered on page load
51102 * - Parent Interface elements may not be loaded before child, so this handles that..
51109 module : 'Pman.Tab.projectMgr',
51111 parent : 'Pman.layout',
51112 disabled : false, // or use a function..
51115 * * @param {Object} details about module
51117 register : function(obj) {
51118 this.modules.push(obj);
51122 * convert a string to an object..
51126 toObject : function(str)
51128 if (!str || typeof(str) == 'object') {
51131 var ar = str.split('.');
51135 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51137 throw "Module not found : " + str;
51139 Roo.each(ar, function(e) {
51140 if (typeof(o[e]) == 'undefined') {
51141 throw "Module not found : " + str;
51151 * move modules into their correct place in the tree..
51154 preBuild : function ()
51157 Roo.each(this.modules , function (obj)
51159 obj.parent = this.toObject(obj.parent);
51162 this.topModule = obj;
51166 if (!obj.parent.modules) {
51167 obj.parent.modules = new Roo.util.MixedCollection(false,
51168 function(o) { return o.order + '' }
51172 obj.parent.modules.add(obj);
51177 * make a list of modules to build.
51178 * @return {Array} list of modules.
51181 buildOrder : function()
51184 var cmp = function(a,b) {
51185 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51188 if (!this.topModule || !this.topModule.modules) {
51189 throw "No top level modules to build";
51192 // make a flat list in order of modules to build.
51193 var mods = [ this.topModule ];
51196 // add modules to their parents..
51197 var addMod = function(m) {
51198 // Roo.debug && Roo.log(m.modKey);
51202 m.modules.keySort('ASC', cmp );
51203 m.modules.each(addMod);
51205 // not sure if this is used any more..
51207 m.finalize.name = m.name + " (clean up) ";
51208 mods.push(m.finalize);
51212 this.topModule.modules.keySort('ASC', cmp );
51213 this.topModule.modules.each(addMod);
51218 * Build the registered modules.
51219 * @param {Object} parent element.
51220 * @param {Function} optional method to call after module has been added.
51228 var mods = this.buildOrder();
51230 //this.allmods = mods;
51231 //Roo.debug && Roo.log(mods);
51233 if (!mods.length) { // should not happen
51234 throw "NO modules!!!";
51239 // flash it up as modal - so we store the mask!?
51240 Roo.MessageBox.show({ title: 'loading' });
51241 Roo.MessageBox.show({
51242 title: "Please wait...",
51243 msg: "Building Interface...",
51250 var total = mods.length;
51253 var progressRun = function() {
51254 if (!mods.length) {
51255 Roo.debug && Roo.log('hide?');
51256 Roo.MessageBox.hide();
51257 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51261 var m = mods.shift();
51262 Roo.debug && Roo.log(m);
51263 if (typeof(m) == 'function') { // not sure if this is supported any more..
51265 return progressRun.defer(10, _this);
51268 Roo.MessageBox.updateProgress(
51269 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51271 (m.name ? (' - ' + m.name) : '')
51276 var disabled = (typeof(m.disabled) == 'function') ?
51277 m.disabled.call(m.module.disabled) : m.disabled;
51281 return progressRun(); // we do not update the display!
51285 // it's a top level one..
51286 var layoutbase = new Ext.BorderLayout(document.body, {
51292 tabPosition: 'top',
51293 //resizeTabs: true,
51294 alwaysShowTabs: true,
51298 var tree = m.tree();
51299 tree.region = 'center';
51300 m.el = layoutbase.addxtype(tree);
51302 m.layout = m.panel.layout;
51303 return progressRun.defer(10, _this);
51306 var tree = m.tree();
51307 tree.region = tree.region || m.region;
51308 m.el = m.parent.el.addxtype(tree);
51309 m.fireEvent('built', m);
51311 m.layout = m.panel.layout;
51312 progressRun.defer(10, _this);
51315 progressRun.defer(1, _this);
51325 //<script type="text/javascript">
51330 * @extends Roo.LayoutDialog
51331 * A generic Login Dialog..... - only one needed in theory!?!?
51333 * Fires XComponent builder on success...
51336 * username,password, lang = for login actions.
51337 * check = 1 for periodic checking that sesion is valid.
51338 * passwordRequest = email request password
51339 * logout = 1 = to logout
51341 * Affects: (this id="????" elements)
51342 * loading (removed) (used to indicate application is loading)
51343 * loading-mask (hides) (used to hide application when it's building loading)
51349 * Myapp.login = Roo.Login({
51365 Roo.Login = function(cfg)
51371 Roo.apply(this,cfg);
51373 Roo.onReady(function() {
51379 Roo.Login.superclass.constructor.call(this, this);
51380 //this.addxtype(this.items[0]);
51386 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51389 * @cfg {String} method
51390 * Method used to query for login details.
51395 * @cfg {String} url
51396 * URL to query login data. - eg. baseURL + '/Login.php'
51402 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51407 * @property checkFails
51408 * Number of times we have attempted to get authentication check, and failed.
51413 * @property intervalID
51414 * The window interval that does the constant login checking.
51420 onLoad : function() // called on page load...
51424 if (Roo.get('loading')) { // clear any loading indicator..
51425 Roo.get('loading').remove();
51428 //this.switchLang('en'); // set the language to english..
51431 success: function(response, opts) { // check successfull...
51433 var res = this.processResponse(response);
51434 this.checkFails =0;
51435 if (!res.success) { // error!
51436 this.checkFails = 5;
51437 //console.log('call failure');
51438 return this.failure(response,opts);
51441 if (!res.data.id) { // id=0 == login failure.
51442 return this.show();
51446 //console.log(success);
51447 this.fillAuth(res.data);
51448 this.checkFails =0;
51449 Roo.XComponent.build();
51451 failure : this.show
51457 check: function(cfg) // called every so often to refresh cookie etc..
51459 if (cfg.again) { // could be undefined..
51462 this.checkFails = 0;
51465 if (this.sending) {
51466 if ( this.checkFails > 4) {
51467 Roo.MessageBox.alert("Error",
51468 "Error getting authentication status. - try reloading, or wait a while", function() {
51469 _this.sending = false;
51474 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51477 this.sending = true;
51484 method: this.method,
51485 success: cfg.success || this.success,
51486 failure : cfg.failure || this.failure,
51496 window.onbeforeunload = function() { }; // false does not work for IE..
51506 failure : function() {
51507 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51508 document.location = document.location.toString() + '?ts=' + Math.random();
51512 success : function() {
51513 _this.user = false;
51514 this.checkFails =0;
51516 document.location = document.location.toString() + '?ts=' + Math.random();
51523 processResponse : function (response)
51527 res = Roo.decode(response.responseText);
51529 if (typeof(res) != 'object') {
51530 res = { success : false, errorMsg : res, errors : true };
51532 if (typeof(res.success) == 'undefined') {
51533 res.success = false;
51537 res = { success : false, errorMsg : response.responseText, errors : true };
51542 success : function(response, opts) // check successfull...
51544 this.sending = false;
51545 var res = this.processResponse(response);
51546 if (!res.success) {
51547 return this.failure(response, opts);
51549 if (!res.data || !res.data.id) {
51550 return this.failure(response,opts);
51552 //console.log(res);
51553 this.fillAuth(res.data);
51555 this.checkFails =0;
51560 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51562 this.authUser = -1;
51563 this.sending = false;
51564 var res = this.processResponse(response);
51565 //console.log(res);
51566 if ( this.checkFails > 2) {
51568 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51569 "Error getting authentication status. - try reloading");
51572 opts.callCfg.again = true;
51573 this.check.defer(1000, this, [ opts.callCfg ]);
51579 fillAuth: function(au) {
51580 this.startAuthCheck();
51581 this.authUserId = au.id;
51582 this.authUser = au;
51583 this.lastChecked = new Date();
51584 this.fireEvent('refreshed', au);
51585 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51586 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51587 au.lang = au.lang || 'en';
51588 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51589 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51590 this.switchLang(au.lang );
51593 // open system... - -on setyp..
51594 if (this.authUserId < 0) {
51595 Roo.MessageBox.alert("Warning",
51596 "This is an open system - please set up a admin user with a password.");
51599 //Pman.onload(); // which should do nothing if it's a re-auth result...
51604 startAuthCheck : function() // starter for timeout checking..
51606 if (this.intervalID) { // timer already in place...
51610 this.intervalID = window.setInterval(function() {
51611 _this.check(false);
51612 }, 120000); // every 120 secs = 2mins..
51618 switchLang : function (lang)
51620 _T = typeof(_T) == 'undefined' ? false : _T;
51621 if (!_T || !lang.length) {
51625 if (!_T && lang != 'en') {
51626 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51630 if (typeof(_T.en) == 'undefined') {
51632 Roo.apply(_T.en, _T);
51635 if (typeof(_T[lang]) == 'undefined') {
51636 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51641 Roo.apply(_T, _T[lang]);
51642 // just need to set the text values for everything...
51644 /* this will not work ...
51648 function formLabel(name, val) {
51649 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51652 formLabel('password', "Password"+':');
51653 formLabel('username', "Email Address"+':');
51654 formLabel('lang', "Language"+':');
51655 this.dialog.setTitle("Login");
51656 this.dialog.buttons[0].setText("Forgot Password");
51657 this.dialog.buttons[1].setText("Login");
51676 collapsible: false,
51678 center: { // needed??
51681 // tabPosition: 'top',
51684 alwaysShowTabs: false
51688 show : function(dlg)
51690 //console.log(this);
51691 this.form = this.layout.getRegion('center').activePanel.form;
51692 this.form.dialog = dlg;
51693 this.buttons[0].form = this.form;
51694 this.buttons[0].dialog = dlg;
51695 this.buttons[1].form = this.form;
51696 this.buttons[1].dialog = dlg;
51698 //this.resizeToLogo.defer(1000,this);
51699 // this is all related to resizing for logos..
51700 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51702 // this.resizeToLogo.defer(1000,this);
51705 //var w = Ext.lib.Dom.getViewWidth() - 100;
51706 //var h = Ext.lib.Dom.getViewHeight() - 100;
51707 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51709 if (this.disabled) {
51714 if (this.user.id < 0) { // used for inital setup situations.
51718 if (this.intervalID) {
51719 // remove the timer
51720 window.clearInterval(this.intervalID);
51721 this.intervalID = false;
51725 if (Roo.get('loading')) {
51726 Roo.get('loading').remove();
51728 if (Roo.get('loading-mask')) {
51729 Roo.get('loading-mask').hide();
51732 //incomming._node = tnode;
51734 //this.dialog.modal = !modal;
51735 //this.dialog.show();
51739 this.form.setValues({
51740 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
51741 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
51744 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
51745 if (this.form.findField('username').getValue().length > 0 ){
51746 this.form.findField('password').focus();
51748 this.form.findField('username').focus();
51756 xtype : 'ContentPanel',
51768 style : 'margin: 10px;',
51771 actionfailed : function(f, act) {
51772 // form can return { errors: .... }
51774 //act.result.errors // invalid form element list...
51775 //act.result.errorMsg// invalid form element list...
51777 this.dialog.el.unmask();
51778 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
51779 "Login failed - communication error - try again.");
51782 actioncomplete: function(re, act) {
51784 Roo.state.Manager.set(
51785 this.dialog.realm + '.username',
51786 this.findField('username').getValue()
51788 Roo.state.Manager.set(
51789 this.dialog.realm + '.lang',
51790 this.findField('lang').getValue()
51793 this.dialog.fillAuth(act.result.data);
51795 this.dialog.hide();
51797 if (Roo.get('loading-mask')) {
51798 Roo.get('loading-mask').show();
51800 Roo.XComponent.build();
51808 xtype : 'TextField',
51810 fieldLabel: "Email Address",
51813 autoCreate : {tag: "input", type: "text", size: "20"}
51816 xtype : 'TextField',
51818 fieldLabel: "Password",
51819 inputType: 'password',
51822 autoCreate : {tag: "input", type: "text", size: "20"},
51824 specialkey : function(e,ev) {
51825 if (ev.keyCode == 13) {
51826 this.form.dialog.el.mask("Logging in");
51827 this.form.doAction('submit', {
51828 url: this.form.dialog.url,
51829 method: this.form.dialog.method
51836 xtype : 'ComboBox',
51838 fieldLabel: "Language",
51841 xtype : 'SimpleStore',
51842 fields: ['lang', 'ldisp'],
51844 [ 'en', 'English' ],
51845 [ 'zh_HK' , '\u7E41\u4E2D' ],
51846 [ 'zh_CN', '\u7C21\u4E2D' ]
51850 valueField : 'lang',
51851 hiddenName: 'lang',
51853 displayField:'ldisp',
51857 triggerAction: 'all',
51858 emptyText:'Select a Language...',
51859 selectOnFocus:true,
51861 select : function(cb, rec, ix) {
51862 this.form.switchLang(rec.data.lang);
51878 text : "Forgot Password",
51880 click : function() {
51881 //console.log(this);
51882 var n = this.form.findField('username').getValue();
51884 Roo.MessageBox.alert("Error", "Fill in your email address");
51888 url: this.dialog.url,
51892 method: this.dialog.method,
51893 success: function(response, opts) { // check successfull...
51895 var res = this.dialog.processResponse(response);
51896 if (!res.success) { // error!
51897 Roo.MessageBox.alert("Error" ,
51898 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
51901 Roo.MessageBox.alert("Notice" ,
51902 "Please check you email for the Password Reset message");
51904 failure : function() {
51905 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
51918 click : function () {
51920 this.dialog.el.mask("Logging in");
51921 this.form.doAction('submit', {
51922 url: this.dialog.url,
51923 method: this.dialog.method