4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1010 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1011 T CST Timezone setting of the machine running the code
1012 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1015 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d')); //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1020 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1023 * Here are some standard date/time patterns that you might find helpful. They
1024 * are not part of the source of Date.js, but to use them you can simply copy this
1025 * block of code into any script that is included after Date.js and they will also become
1026 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1029 ISO8601Long:"Y-m-d H:i:s",
1030 ISO8601Short:"Y-m-d",
1032 LongDate: "l, F d, Y",
1033 FullDateTime: "l, F d, Y g:i:s A",
1036 LongTime: "g:i:s A",
1037 SortableDateTime: "Y-m-d\\TH:i:s",
1038 UniversalSortableDateTime: "Y-m-d H:i:sO",
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1051 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052 * They generate precompiled functions from date formats instead of parsing and
1053 * processing the pattern every time you format a date. These functions are available
1054 * on every Date object (any javascript function).
1056 * The original article and download are here:
1057 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1064 Returns the number of milliseconds between this date and date
1065 @param {Date} date (optional) Defaults to now
1066 @return {Number} The diff in milliseconds
1067 @member Date getElapsed
1069 Date.prototype.getElapsed = function(date) {
1070 return Math.abs((date || new Date()).getTime()-this.getTime());
1072 // was in date file..
1076 Date.parseFunctions = {count:0};
1078 Date.parseRegexes = [];
1080 Date.formatFunctions = {count:0};
1083 Date.prototype.dateFormat = function(format) {
1084 if (Date.formatFunctions[format] == null) {
1085 Date.createNewFormat(format);
1087 var func = Date.formatFunctions[format];
1088 return this[func]();
1093 * Formats a date given the supplied format string
1094 * @param {String} format The format string
1095 * @return {String} The formatted date
1098 Date.prototype.format = Date.prototype.dateFormat;
1101 Date.createNewFormat = function(format) {
1102 var funcName = "format" + Date.formatFunctions.count++;
1103 Date.formatFunctions[format] = funcName;
1104 var code = "Date.prototype." + funcName + " = function(){return ";
1105 var special = false;
1107 for (var i = 0; i < format.length; ++i) {
1108 ch = format.charAt(i);
1109 if (!special && ch == "\\") {
1114 code += "'" + String.escape(ch) + "' + ";
1117 code += Date.getFormatCode(ch);
1120 /** eval:var:zzzzzzzzzzzzz */
1121 eval(code.substring(0, code.length - 3) + ";}");
1125 Date.getFormatCode = function(character) {
1126 switch (character) {
1128 return "String.leftPad(this.getDate(), 2, '0') + ";
1130 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1132 return "this.getDate() + ";
1134 return "Date.dayNames[this.getDay()] + ";
1136 return "this.getSuffix() + ";
1138 return "this.getDay() + ";
1140 return "this.getDayOfYear() + ";
1142 return "this.getWeekOfYear() + ";
1144 return "Date.monthNames[this.getMonth()] + ";
1146 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1148 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1150 return "(this.getMonth() + 1) + ";
1152 return "this.getDaysInMonth() + ";
1154 return "(this.isLeapYear() ? 1 : 0) + ";
1156 return "this.getFullYear() + ";
1158 return "('' + this.getFullYear()).substring(2, 4) + ";
1160 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1162 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1164 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1166 return "this.getHours() + ";
1168 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1170 return "String.leftPad(this.getHours(), 2, '0') + ";
1172 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1174 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1176 return "this.getGMTOffset() + ";
1178 return "this.getGMTColonOffset() + ";
1180 return "this.getTimezone() + ";
1182 return "(this.getTimezoneOffset() * -60) + ";
1184 return "'" + String.escape(character) + "' + ";
1189 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1191 * the date format that is not specified will default to the current date value for that part. Time parts can also
1192 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1193 * string or the parse operation will fail.
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1208 * @param {String} input The unparsed date as a string
1209 * @param {String} format The format the date is in
1210 * @return {Date} The parsed date
1213 Date.parseDate = function(input, format) {
1214 if (Date.parseFunctions[format] == null) {
1215 Date.createParser(format);
1217 var func = Date.parseFunctions[format];
1218 return Date[func](input);
1223 Date.createParser = function(format) {
1224 var funcName = "parse" + Date.parseFunctions.count++;
1225 var regexNum = Date.parseRegexes.length;
1226 var currentGroup = 1;
1227 Date.parseFunctions[format] = funcName;
1229 var code = "Date." + funcName + " = function(input){\n"
1230 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231 + "var d = new Date();\n"
1232 + "y = d.getFullYear();\n"
1233 + "m = d.getMonth();\n"
1234 + "d = d.getDate();\n"
1235 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236 + "if (results && results.length > 0) {";
1239 var special = false;
1241 for (var i = 0; i < format.length; ++i) {
1242 ch = format.charAt(i);
1243 if (!special && ch == "\\") {
1248 regex += String.escape(ch);
1251 var obj = Date.formatCodeToRegex(ch, currentGroup);
1252 currentGroup += obj.g;
1254 if (obj.g && obj.c) {
1260 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261 + "{v = new Date(y, m, d, h, i, s);}\n"
1262 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265 + "{v = new Date(y, m, d, h);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267 + "{v = new Date(y, m, d);}\n"
1268 + "else if (y >= 0 && m >= 0)\n"
1269 + "{v = new Date(y, m);}\n"
1270 + "else if (y >= 0)\n"
1271 + "{v = new Date(y);}\n"
1272 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278 /** eval:var:zzzzzzzzzzzzz */
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284 switch (character) {
1288 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292 s:"(\\d{1,2})"}; // day of month without leading zeroes
1295 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296 s:"(\\d{2})"}; // day of month with leading zeroes
1300 s:"(?:" + Date.dayNames.join("|") + ")"};
1304 s:"(?:st|nd|rd|th)"};
1319 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320 s:"(" + Date.monthNames.join("|") + ")"};
1323 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1343 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1347 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1352 c:"if (results[" + currentGroup + "] == 'am') {\n"
1353 + "if (h == 12) { h = 0; }\n"
1354 + "} else { if (h < 12) { h += 12; }}",
1358 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1365 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1374 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1378 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1383 "o = results[", currentGroup, "];\n",
1384 "var sn = o.substring(0,1);\n", // get + / - sign
1385 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1390 s:"([+\-]\\d{2,4})"};
1396 "o = results[", currentGroup, "];\n",
1397 "var sn = o.substring(0,1);\n",
1398 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1399 "var mn = o.substring(4,6) % 60;\n",
1400 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1401 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1411 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1412 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1416 s:String.escape(character)};
1421 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1422 * @return {String} The abbreviated timezone name (e.g. 'CST')
1424 Date.prototype.getTimezone = function() {
1425 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1429 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1430 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1432 Date.prototype.getGMTOffset = function() {
1433 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1434 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1435 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1439 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1440 * @return {String} 2-characters representing hours and 2-characters representing minutes
1441 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1443 Date.prototype.getGMTColonOffset = function() {
1444 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1445 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1447 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1451 * Get the numeric day number of the year, adjusted for leap year.
1452 * @return {Number} 0 through 364 (365 in leap years)
1454 Date.prototype.getDayOfYear = function() {
1456 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1457 for (var i = 0; i < this.getMonth(); ++i) {
1458 num += Date.daysInMonth[i];
1460 return num + this.getDate() - 1;
1464 * Get the string representation of the numeric week number of the year
1465 * (equivalent to the format specifier 'W').
1466 * @return {String} '00' through '52'
1468 Date.prototype.getWeekOfYear = function() {
1469 // Skip to Thursday of this week
1470 var now = this.getDayOfYear() + (4 - this.getDay());
1471 // Find the first Thursday of the year
1472 var jan1 = new Date(this.getFullYear(), 0, 1);
1473 var then = (7 - jan1.getDay() + 4);
1474 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1478 * Whether or not the current date is in a leap year.
1479 * @return {Boolean} True if the current date is in a leap year, else false
1481 Date.prototype.isLeapYear = function() {
1482 var year = this.getFullYear();
1483 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1487 * Get the first day of the current month, adjusted for leap year. The returned value
1488 * is the numeric day index within the week (0-6) which can be used in conjunction with
1489 * the {@link #monthNames} array to retrieve the textual day name.
1492 var dt = new Date('1/10/2007');
1493 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1495 * @return {Number} The day number (0-6)
1497 Date.prototype.getFirstDayOfMonth = function() {
1498 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1499 return (day < 0) ? (day + 7) : day;
1503 * Get the last day of the current month, adjusted for leap year. The returned value
1504 * is the numeric day index within the week (0-6) which can be used in conjunction with
1505 * the {@link #monthNames} array to retrieve the textual day name.
1508 var dt = new Date('1/10/2007');
1509 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1511 * @return {Number} The day number (0-6)
1513 Date.prototype.getLastDayOfMonth = function() {
1514 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1515 return (day < 0) ? (day + 7) : day;
1520 * Get the first date of this date's month
1523 Date.prototype.getFirstDateOfMonth = function() {
1524 return new Date(this.getFullYear(), this.getMonth(), 1);
1528 * Get the last date of this date's month
1531 Date.prototype.getLastDateOfMonth = function() {
1532 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 * Get the number of days in the current month, adjusted for leap year.
1536 * @return {Number} The number of days in the month
1538 Date.prototype.getDaysInMonth = function() {
1539 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1540 return Date.daysInMonth[this.getMonth()];
1544 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1545 * @return {String} 'st, 'nd', 'rd' or 'th'
1547 Date.prototype.getSuffix = function() {
1548 switch (this.getDate()) {
1565 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568 * An array of textual month names.
1569 * Override these values for international dates, for example...
1570 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1589 * An array of textual day names.
1590 * Override these values for international dates, for example...
1591 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1607 Date.monthNumbers = {
1622 * Creates and returns a new Date instance with the exact same date value as the called instance.
1623 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1624 * variable will also be changed. When the intention is to create a new variable that will not
1625 * modify the original instance, you should create a clone.
1627 * Example of correctly cloning a date:
1630 var orig = new Date('10/1/2006');
1633 document.write(orig); //returns 'Thu Oct 05 2006'!
1636 var orig = new Date('10/1/2006');
1637 var copy = orig.clone();
1639 document.write(orig); //returns 'Thu Oct 01 2006'
1641 * @return {Date} The new Date instance
1643 Date.prototype.clone = function() {
1644 return new Date(this.getTime());
1648 * Clears any time information from this date
1649 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1650 @return {Date} this or the clone
1652 Date.prototype.clearTime = function(clone){
1654 return this.clone().clearTime();
1659 this.setMilliseconds(0);
1664 // safari setMonth is broken
1666 Date.brokenSetMonth = Date.prototype.setMonth;
1667 Date.prototype.setMonth = function(num){
1669 var n = Math.ceil(-num);
1670 var back_year = Math.ceil(n/12);
1671 var month = (n % 12) ? 12 - n % 12 : 0 ;
1672 this.setFullYear(this.getFullYear() - back_year);
1673 return Date.brokenSetMonth.call(this, month);
1675 return Date.brokenSetMonth.apply(this, arguments);
1680 /** Date interval constant
1684 /** Date interval constant
1688 /** Date interval constant
1692 /** Date interval constant
1696 /** Date interval constant
1700 /** Date interval constant
1704 /** Date interval constant
1710 * Provides a convenient method of performing basic date arithmetic. This method
1711 * does not modify the Date instance being called - it creates and returns
1712 * a new Date instance containing the resulting date value.
1717 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1718 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1720 //Negative values will subtract correctly:
1721 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1722 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1724 //You can even chain several calls together in one line!
1725 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1726 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729 * @param {String} interval A valid date interval enum value
1730 * @param {Number} value The amount to add to the current date
1731 * @return {Date} The new Date instance
1733 Date.prototype.add = function(interval, value){
1734 var d = this.clone();
1735 if (!interval || value === 0) return d;
1736 switch(interval.toLowerCase()){
1738 d.setMilliseconds(this.getMilliseconds() + value);
1741 d.setSeconds(this.getSeconds() + value);
1744 d.setMinutes(this.getMinutes() + value);
1747 d.setHours(this.getHours() + value);
1750 d.setDate(this.getDate() + value);
1753 var day = this.getDate();
1755 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758 d.setMonth(this.getMonth() + value);
1761 d.setFullYear(this.getFullYear() + value);
1768 * Ext JS Library 1.1.1
1769 * Copyright(c) 2006-2007, Ext JS, LLC.
1771 * Originally Released Under LGPL - original licence link has changed is not relivant.
1774 * <script type="text/javascript">
1778 getViewWidth : function(full) {
1779 return full ? this.getDocumentWidth() : this.getViewportWidth();
1782 getViewHeight : function(full) {
1783 return full ? this.getDocumentHeight() : this.getViewportHeight();
1786 getDocumentHeight: function() {
1787 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1788 return Math.max(scrollHeight, this.getViewportHeight());
1791 getDocumentWidth: function() {
1792 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1793 return Math.max(scrollWidth, this.getViewportWidth());
1796 getViewportHeight: function() {
1797 var height = self.innerHeight;
1798 var mode = document.compatMode;
1800 if ((mode || Roo.isIE) && !Roo.isOpera) {
1801 height = (mode == "CSS1Compat") ?
1802 document.documentElement.clientHeight :
1803 document.body.clientHeight;
1809 getViewportWidth: function() {
1810 var width = self.innerWidth;
1811 var mode = document.compatMode;
1813 if (mode || Roo.isIE) {
1814 width = (mode == "CSS1Compat") ?
1815 document.documentElement.clientWidth :
1816 document.body.clientWidth;
1821 isAncestor : function(p, c) {
1828 if (p.contains && !Roo.isSafari) {
1829 return p.contains(c);
1830 } else if (p.compareDocumentPosition) {
1831 return !!(p.compareDocumentPosition(c) & 16);
1833 var parent = c.parentNode;
1838 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1841 parent = parent.parentNode;
1847 getRegion : function(el) {
1848 return Roo.lib.Region.getRegion(el);
1851 getY : function(el) {
1852 return this.getXY(el)[1];
1855 getX : function(el) {
1856 return this.getXY(el)[0];
1859 getXY : function(el) {
1860 var p, pe, b, scroll, bd = document.body;
1861 el = Roo.getDom(el);
1862 var fly = Roo.lib.AnimBase.fly;
1863 if (el.getBoundingClientRect) {
1864 b = el.getBoundingClientRect();
1865 scroll = fly(document).getScroll();
1866 return [b.left + scroll.left, b.top + scroll.top];
1872 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1879 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1886 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1887 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1894 if (p != el && pe.getStyle('overflow') != 'visible') {
1902 if (Roo.isSafari && hasAbsolute) {
1907 if (Roo.isGecko && !hasAbsolute) {
1909 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1910 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1914 while (p && p != bd) {
1915 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1927 setXY : function(el, xy) {
1928 el = Roo.fly(el, '_setXY');
1930 var pts = el.translatePoints(xy);
1931 if (xy[0] !== false) {
1932 el.dom.style.left = pts.left + "px";
1934 if (xy[1] !== false) {
1935 el.dom.style.top = pts.top + "px";
1939 setX : function(el, x) {
1940 this.setXY(el, [x, false]);
1943 setY : function(el, y) {
1944 this.setXY(el, [false, y]);
1948 * Portions of this file are based on pieces of Yahoo User Interface Library
1949 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1950 * YUI licensed under the BSD License:
1951 * http://developer.yahoo.net/yui/license.txt
1952 * <script type="text/javascript">
1956 Roo.lib.Event = function() {
1957 var loadComplete = false;
1959 var unloadListeners = [];
1961 var onAvailStack = [];
1963 var lastError = null;
1976 startInterval: function() {
1977 if (!this._interval) {
1979 var callback = function() {
1980 self._tryPreloadAttach();
1982 this._interval = setInterval(callback, this.POLL_INTERVAL);
1987 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1988 onAvailStack.push({ id: p_id,
1991 override: p_override,
1992 checkReady: false });
1994 retryCount = this.POLL_RETRYS;
1995 this.startInterval();
1999 addListener: function(el, eventName, fn) {
2000 el = Roo.getDom(el);
2005 if ("unload" == eventName) {
2006 unloadListeners[unloadListeners.length] =
2007 [el, eventName, fn];
2011 var wrappedFn = function(e) {
2012 return fn(Roo.lib.Event.getEvent(e));
2015 var li = [el, eventName, fn, wrappedFn];
2017 var index = listeners.length;
2018 listeners[index] = li;
2020 this.doAdd(el, eventName, wrappedFn, false);
2026 removeListener: function(el, eventName, fn) {
2029 el = Roo.getDom(el);
2032 return this.purgeElement(el, false, eventName);
2036 if ("unload" == eventName) {
2038 for (i = 0,len = unloadListeners.length; i < len; i++) {
2039 var li = unloadListeners[i];
2042 li[1] == eventName &&
2044 unloadListeners.splice(i, 1);
2052 var cacheItem = null;
2055 var index = arguments[3];
2057 if ("undefined" == typeof index) {
2058 index = this._getCacheIndex(el, eventName, fn);
2062 cacheItem = listeners[index];
2065 if (!el || !cacheItem) {
2069 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2071 delete listeners[index][this.WFN];
2072 delete listeners[index][this.FN];
2073 listeners.splice(index, 1);
2080 getTarget: function(ev, resolveTextNode) {
2081 ev = ev.browserEvent || ev;
2082 var t = ev.target || ev.srcElement;
2083 return this.resolveTextNode(t);
2087 resolveTextNode: function(node) {
2088 if (Roo.isSafari && node && 3 == node.nodeType) {
2089 return node.parentNode;
2096 getPageX: function(ev) {
2097 ev = ev.browserEvent || ev;
2099 if (!x && 0 !== x) {
2100 x = ev.clientX || 0;
2103 x += this.getScroll()[1];
2111 getPageY: function(ev) {
2112 ev = ev.browserEvent || ev;
2114 if (!y && 0 !== y) {
2115 y = ev.clientY || 0;
2118 y += this.getScroll()[0];
2127 getXY: function(ev) {
2128 ev = ev.browserEvent || ev;
2129 return [this.getPageX(ev), this.getPageY(ev)];
2133 getRelatedTarget: function(ev) {
2134 ev = ev.browserEvent || ev;
2135 var t = ev.relatedTarget;
2137 if (ev.type == "mouseout") {
2139 } else if (ev.type == "mouseover") {
2144 return this.resolveTextNode(t);
2148 getTime: function(ev) {
2149 ev = ev.browserEvent || ev;
2151 var t = new Date().getTime();
2155 this.lastError = ex;
2164 stopEvent: function(ev) {
2165 this.stopPropagation(ev);
2166 this.preventDefault(ev);
2170 stopPropagation: function(ev) {
2171 ev = ev.browserEvent || ev;
2172 if (ev.stopPropagation) {
2173 ev.stopPropagation();
2175 ev.cancelBubble = true;
2180 preventDefault: function(ev) {
2181 ev = ev.browserEvent || ev;
2182 if(ev.preventDefault) {
2183 ev.preventDefault();
2185 ev.returnValue = false;
2190 getEvent: function(e) {
2191 var ev = e || window.event;
2193 var c = this.getEvent.caller;
2195 ev = c.arguments[0];
2196 if (ev && Event == ev.constructor) {
2206 getCharCode: function(ev) {
2207 ev = ev.browserEvent || ev;
2208 return ev.charCode || ev.keyCode || 0;
2212 _getCacheIndex: function(el, eventName, fn) {
2213 for (var i = 0,len = listeners.length; i < len; ++i) {
2214 var li = listeners[i];
2216 li[this.FN] == fn &&
2217 li[this.EL] == el &&
2218 li[this.TYPE] == eventName) {
2230 getEl: function(id) {
2231 return document.getElementById(id);
2235 clearCache: function() {
2239 _load: function(e) {
2240 loadComplete = true;
2241 var EU = Roo.lib.Event;
2245 EU.doRemove(window, "load", EU._load);
2250 _tryPreloadAttach: function() {
2259 var tryAgain = !loadComplete;
2261 tryAgain = (retryCount > 0);
2266 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2267 var item = onAvailStack[i];
2269 var el = this.getEl(item.id);
2272 if (!item.checkReady ||
2275 (document && document.body)) {
2278 if (item.override) {
2279 if (item.override === true) {
2282 scope = item.override;
2285 item.fn.call(scope, item.obj);
2286 onAvailStack[i] = null;
2289 notAvail.push(item);
2294 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2298 this.startInterval();
2300 clearInterval(this._interval);
2301 this._interval = null;
2304 this.locked = false;
2311 purgeElement: function(el, recurse, eventName) {
2312 var elListeners = this.getListeners(el, eventName);
2314 for (var i = 0,len = elListeners.length; i < len; ++i) {
2315 var l = elListeners[i];
2316 this.removeListener(el, l.type, l.fn);
2320 if (recurse && el && el.childNodes) {
2321 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2322 this.purgeElement(el.childNodes[i], recurse, eventName);
2328 getListeners: function(el, eventName) {
2329 var results = [], searchLists;
2331 searchLists = [listeners, unloadListeners];
2332 } else if (eventName == "unload") {
2333 searchLists = [unloadListeners];
2335 searchLists = [listeners];
2338 for (var j = 0; j < searchLists.length; ++j) {
2339 var searchList = searchLists[j];
2340 if (searchList && searchList.length > 0) {
2341 for (var i = 0,len = searchList.length; i < len; ++i) {
2342 var l = searchList[i];
2343 if (l && l[this.EL] === el &&
2344 (!eventName || eventName === l[this.TYPE])) {
2349 adjust: l[this.ADJ_SCOPE],
2357 return (results.length) ? results : null;
2361 _unload: function(e) {
2363 var EU = Roo.lib.Event, i, j, l, len, index;
2365 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2366 l = unloadListeners[i];
2369 if (l[EU.ADJ_SCOPE]) {
2370 if (l[EU.ADJ_SCOPE] === true) {
2373 scope = l[EU.ADJ_SCOPE];
2376 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2377 unloadListeners[i] = null;
2383 unloadListeners = null;
2385 if (listeners && listeners.length > 0) {
2386 j = listeners.length;
2389 l = listeners[index];
2391 EU.removeListener(l[EU.EL], l[EU.TYPE],
2401 EU.doRemove(window, "unload", EU._unload);
2406 getScroll: function() {
2407 var dd = document.documentElement, db = document.body;
2408 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2409 return [dd.scrollTop, dd.scrollLeft];
2411 return [db.scrollTop, db.scrollLeft];
2418 doAdd: function () {
2419 if (window.addEventListener) {
2420 return function(el, eventName, fn, capture) {
2421 el.addEventListener(eventName, fn, (capture));
2423 } else if (window.attachEvent) {
2424 return function(el, eventName, fn, capture) {
2425 el.attachEvent("on" + eventName, fn);
2434 doRemove: function() {
2435 if (window.removeEventListener) {
2436 return function (el, eventName, fn, capture) {
2437 el.removeEventListener(eventName, fn, (capture));
2439 } else if (window.detachEvent) {
2440 return function (el, eventName, fn) {
2441 el.detachEvent("on" + eventName, fn);
2453 var E = Roo.lib.Event;
2454 E.on = E.addListener;
2455 E.un = E.removeListener;
2457 if (document && document.body) {
2460 E.doAdd(window, "load", E._load);
2462 E.doAdd(window, "unload", E._unload);
2463 E._tryPreloadAttach();
2467 * Portions of this file are based on pieces of Yahoo User Interface Library
2468 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2469 * YUI licensed under the BSD License:
2470 * http://developer.yahoo.net/yui/license.txt
2471 * <script type="text/javascript">
2477 * @class Roo.lib.Ajax
2484 request : function(method, uri, cb, data, options) {
2486 var hs = options.headers;
2489 if(hs.hasOwnProperty(h)){
2490 this.initHeader(h, hs[h], false);
2494 if(options.xmlData){
2495 this.initHeader('Content-Type', 'text/xml', false);
2497 data = options.xmlData;
2501 return this.asyncRequest(method, uri, cb, data);
2504 serializeForm : function(form) {
2505 if(typeof form == 'string') {
2506 form = (document.getElementById(form) || document.forms[form]);
2509 var el, name, val, disabled, data = '', hasSubmit = false;
2510 for (var i = 0; i < form.elements.length; i++) {
2511 el = form.elements[i];
2512 disabled = form.elements[i].disabled;
2513 name = form.elements[i].name;
2514 val = form.elements[i].value;
2516 if (!disabled && name){
2520 case 'select-multiple':
2521 for (var j = 0; j < el.options.length; j++) {
2522 if (el.options[j].selected) {
2524 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2527 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2535 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2548 if(hasSubmit == false) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2554 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2559 data = data.substr(0, data.length - 1);
2567 useDefaultHeader:true,
2569 defaultPostHeader:'application/x-www-form-urlencoded',
2571 useDefaultXhrHeader:true,
2573 defaultXhrHeader:'XMLHttpRequest',
2575 hasDefaultHeaders:true,
2587 setProgId:function(id)
2589 this.activeX.unshift(id);
2592 setDefaultPostHeader:function(b)
2594 this.useDefaultHeader = b;
2597 setDefaultXhrHeader:function(b)
2599 this.useDefaultXhrHeader = b;
2602 setPollingInterval:function(i)
2604 if (typeof i == 'number' && isFinite(i)) {
2605 this.pollInterval = i;
2609 createXhrObject:function(transactionId)
2615 http = new XMLHttpRequest();
2617 obj = { conn:http, tId:transactionId };
2621 for (var i = 0; i < this.activeX.length; ++i) {
2625 http = new ActiveXObject(this.activeX[i]);
2627 obj = { conn:http, tId:transactionId };
2640 getConnectionObject:function()
2643 var tId = this.transactionId;
2647 o = this.createXhrObject(tId);
2649 this.transactionId++;
2660 asyncRequest:function(method, uri, callback, postData)
2662 var o = this.getConnectionObject();
2668 o.conn.open(method, uri, true);
2670 if (this.useDefaultXhrHeader) {
2671 if (!this.defaultHeaders['X-Requested-With']) {
2672 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2676 if(postData && this.useDefaultHeader){
2677 this.initHeader('Content-Type', this.defaultPostHeader);
2680 if (this.hasDefaultHeaders || this.hasHeaders) {
2684 this.handleReadyState(o, callback);
2685 o.conn.send(postData || null);
2691 handleReadyState:function(o, callback)
2695 if (callback && callback.timeout) {
2696 this.timeout[o.tId] = window.setTimeout(function() {
2697 oConn.abort(o, callback, true);
2698 }, callback.timeout);
2701 this.poll[o.tId] = window.setInterval(
2703 if (o.conn && o.conn.readyState == 4) {
2704 window.clearInterval(oConn.poll[o.tId]);
2705 delete oConn.poll[o.tId];
2707 if(callback && callback.timeout) {
2708 window.clearTimeout(oConn.timeout[o.tId]);
2709 delete oConn.timeout[o.tId];
2712 oConn.handleTransactionResponse(o, callback);
2715 , this.pollInterval);
2718 handleTransactionResponse:function(o, callback, isAbort)
2722 this.releaseObject(o);
2726 var httpStatus, responseObject;
2730 if (o.conn.status !== undefined && o.conn.status != 0) {
2731 httpStatus = o.conn.status;
2743 if (httpStatus >= 200 && httpStatus < 300) {
2744 responseObject = this.createResponseObject(o, callback.argument);
2745 if (callback.success) {
2746 if (!callback.scope) {
2747 callback.success(responseObject);
2752 callback.success.apply(callback.scope, [responseObject]);
2757 switch (httpStatus) {
2765 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2766 if (callback.failure) {
2767 if (!callback.scope) {
2768 callback.failure(responseObject);
2771 callback.failure.apply(callback.scope, [responseObject]);
2776 responseObject = this.createResponseObject(o, callback.argument);
2777 if (callback.failure) {
2778 if (!callback.scope) {
2779 callback.failure(responseObject);
2782 callback.failure.apply(callback.scope, [responseObject]);
2788 this.releaseObject(o);
2789 responseObject = null;
2792 createResponseObject:function(o, callbackArg)
2799 var headerStr = o.conn.getAllResponseHeaders();
2800 var header = headerStr.split('\n');
2801 for (var i = 0; i < header.length; i++) {
2802 var delimitPos = header[i].indexOf(':');
2803 if (delimitPos != -1) {
2804 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2812 obj.status = o.conn.status;
2813 obj.statusText = o.conn.statusText;
2814 obj.getResponseHeader = headerObj;
2815 obj.getAllResponseHeaders = headerStr;
2816 obj.responseText = o.conn.responseText;
2817 obj.responseXML = o.conn.responseXML;
2819 if (typeof callbackArg !== undefined) {
2820 obj.argument = callbackArg;
2826 createExceptionObject:function(tId, callbackArg, isAbort)
2829 var COMM_ERROR = 'communication failure';
2830 var ABORT_CODE = -1;
2831 var ABORT_ERROR = 'transaction aborted';
2837 obj.status = ABORT_CODE;
2838 obj.statusText = ABORT_ERROR;
2841 obj.status = COMM_CODE;
2842 obj.statusText = COMM_ERROR;
2846 obj.argument = callbackArg;
2852 initHeader:function(label, value, isDefault)
2854 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2856 if (headerObj[label] === undefined) {
2857 headerObj[label] = value;
2862 headerObj[label] = value + "," + headerObj[label];
2866 this.hasDefaultHeaders = true;
2869 this.hasHeaders = true;
2874 setHeader:function(o)
2876 if (this.hasDefaultHeaders) {
2877 for (var prop in this.defaultHeaders) {
2878 if (this.defaultHeaders.hasOwnProperty(prop)) {
2879 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2884 if (this.hasHeaders) {
2885 for (var prop in this.headers) {
2886 if (this.headers.hasOwnProperty(prop)) {
2887 o.conn.setRequestHeader(prop, this.headers[prop]);
2891 this.hasHeaders = false;
2895 resetDefaultHeaders:function() {
2896 delete this.defaultHeaders;
2897 this.defaultHeaders = {};
2898 this.hasDefaultHeaders = false;
2901 abort:function(o, callback, isTimeout)
2903 if(this.isCallInProgress(o)) {
2905 window.clearInterval(this.poll[o.tId]);
2906 delete this.poll[o.tId];
2908 delete this.timeout[o.tId];
2911 this.handleTransactionResponse(o, callback, true);
2921 isCallInProgress:function(o)
2924 return o.conn.readyState != 4 && o.conn.readyState != 0;
2933 releaseObject:function(o)
2942 'MSXML2.XMLHTTP.3.0',
2950 * Portions of this file are based on pieces of Yahoo User Interface Library
2951 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2952 * YUI licensed under the BSD License:
2953 * http://developer.yahoo.net/yui/license.txt
2954 * <script type="text/javascript">
2958 Roo.lib.Region = function(t, r, b, l) {
2968 Roo.lib.Region.prototype = {
2969 contains : function(region) {
2970 return ( region.left >= this.left &&
2971 region.right <= this.right &&
2972 region.top >= this.top &&
2973 region.bottom <= this.bottom );
2977 getArea : function() {
2978 return ( (this.bottom - this.top) * (this.right - this.left) );
2981 intersect : function(region) {
2982 var t = Math.max(this.top, region.top);
2983 var r = Math.min(this.right, region.right);
2984 var b = Math.min(this.bottom, region.bottom);
2985 var l = Math.max(this.left, region.left);
2987 if (b >= t && r >= l) {
2988 return new Roo.lib.Region(t, r, b, l);
2993 union : function(region) {
2994 var t = Math.min(this.top, region.top);
2995 var r = Math.max(this.right, region.right);
2996 var b = Math.max(this.bottom, region.bottom);
2997 var l = Math.min(this.left, region.left);
2999 return new Roo.lib.Region(t, r, b, l);
3002 adjust : function(t, l, b, r) {
3011 Roo.lib.Region.getRegion = function(el) {
3012 var p = Roo.lib.Dom.getXY(el);
3015 var r = p[0] + el.offsetWidth;
3016 var b = p[1] + el.offsetHeight;
3019 return new Roo.lib.Region(t, r, b, l);
3022 * Portions of this file are based on pieces of Yahoo User Interface Library
3023 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3024 * YUI licensed under the BSD License:
3025 * http://developer.yahoo.net/yui/license.txt
3026 * <script type="text/javascript">
3029 //@@dep Roo.lib.Region
3032 Roo.lib.Point = function(x, y) {
3033 if (x instanceof Array) {
3037 this.x = this.right = this.left = this[0] = x;
3038 this.y = this.top = this.bottom = this[1] = y;
3041 Roo.lib.Point.prototype = new Roo.lib.Region();
3043 * Portions of this file are based on pieces of Yahoo User Interface Library
3044 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3045 * YUI licensed under the BSD License:
3046 * http://developer.yahoo.net/yui/license.txt
3047 * <script type="text/javascript">
3054 scroll : function(el, args, duration, easing, cb, scope) {
3055 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3058 motion : function(el, args, duration, easing, cb, scope) {
3059 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3062 color : function(el, args, duration, easing, cb, scope) {
3063 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3066 run : function(el, args, duration, easing, cb, scope, type) {
3067 type = type || Roo.lib.AnimBase;
3068 if (typeof easing == "string") {
3069 easing = Roo.lib.Easing[easing];
3071 var anim = new type(el, args, duration, easing);
3072 anim.animateX(function() {
3073 Roo.callback(cb, scope);
3079 * Portions of this file are based on pieces of Yahoo User Interface Library
3080 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3081 * YUI licensed under the BSD License:
3082 * http://developer.yahoo.net/yui/license.txt
3083 * <script type="text/javascript">
3091 if (!libFlyweight) {
3092 libFlyweight = new Roo.Element.Flyweight();
3094 libFlyweight.dom = el;
3095 return libFlyweight;
3098 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3102 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3104 this.init(el, attributes, duration, method);
3108 Roo.lib.AnimBase.fly = fly;
3112 Roo.lib.AnimBase.prototype = {
3114 toString: function() {
3115 var el = this.getEl();
3116 var id = el.id || el.tagName;
3117 return ("Anim " + id);
3121 noNegatives: /width|height|opacity|padding/i,
3122 offsetAttribute: /^((width|height)|(top|left))$/,
3123 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3124 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3128 doMethod: function(attr, start, end) {
3129 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3133 setAttribute: function(attr, val, unit) {
3134 if (this.patterns.noNegatives.test(attr)) {
3135 val = (val > 0) ? val : 0;
3138 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3142 getAttribute: function(attr) {
3143 var el = this.getEl();
3144 var val = fly(el).getStyle(attr);
3146 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3147 return parseFloat(val);
3150 var a = this.patterns.offsetAttribute.exec(attr) || [];
3151 var pos = !!( a[3] );
3152 var box = !!( a[2] );
3155 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3156 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3165 getDefaultUnit: function(attr) {
3166 if (this.patterns.defaultUnit.test(attr)) {
3173 animateX : function(callback, scope) {
3174 var f = function() {
3175 this.onComplete.removeListener(f);
3176 if (typeof callback == "function") {
3177 callback.call(scope || this, this);
3180 this.onComplete.addListener(f, this);
3185 setRuntimeAttribute: function(attr) {
3188 var attributes = this.attributes;
3190 this.runtimeAttributes[attr] = {};
3192 var isset = function(prop) {
3193 return (typeof prop !== 'undefined');
3196 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3200 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3203 if (isset(attributes[attr]['to'])) {
3204 end = attributes[attr]['to'];
3205 } else if (isset(attributes[attr]['by'])) {
3206 if (start.constructor == Array) {
3208 for (var i = 0, len = start.length; i < len; ++i) {
3209 end[i] = start[i] + attributes[attr]['by'][i];
3212 end = start + attributes[attr]['by'];
3216 this.runtimeAttributes[attr].start = start;
3217 this.runtimeAttributes[attr].end = end;
3220 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3224 init: function(el, attributes, duration, method) {
3226 var isAnimated = false;
3229 var startTime = null;
3232 var actualFrames = 0;
3235 el = Roo.getDom(el);
3238 this.attributes = attributes || {};
3241 this.duration = duration || 1;
3244 this.method = method || Roo.lib.Easing.easeNone;
3247 this.useSeconds = true;
3250 this.currentFrame = 0;
3253 this.totalFrames = Roo.lib.AnimMgr.fps;
3256 this.getEl = function() {
3261 this.isAnimated = function() {
3266 this.getStartTime = function() {
3270 this.runtimeAttributes = {};
3273 this.animate = function() {
3274 if (this.isAnimated()) {
3278 this.currentFrame = 0;
3280 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3282 Roo.lib.AnimMgr.registerElement(this);
3286 this.stop = function(finish) {
3288 this.currentFrame = this.totalFrames;
3289 this._onTween.fire();
3291 Roo.lib.AnimMgr.stop(this);
3294 var onStart = function() {
3295 this.onStart.fire();
3297 this.runtimeAttributes = {};
3298 for (var attr in this.attributes) {
3299 this.setRuntimeAttribute(attr);
3304 startTime = new Date();
3308 var onTween = function() {
3310 duration: new Date() - this.getStartTime(),
3311 currentFrame: this.currentFrame
3314 data.toString = function() {
3316 'duration: ' + data.duration +
3317 ', currentFrame: ' + data.currentFrame
3321 this.onTween.fire(data);
3323 var runtimeAttributes = this.runtimeAttributes;
3325 for (var attr in runtimeAttributes) {
3326 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3332 var onComplete = function() {
3333 var actual_duration = (new Date() - startTime) / 1000 ;
3336 duration: actual_duration,
3337 frames: actualFrames,
3338 fps: actualFrames / actual_duration
3341 data.toString = function() {
3343 'duration: ' + data.duration +
3344 ', frames: ' + data.frames +
3345 ', fps: ' + data.fps
3351 this.onComplete.fire(data);
3355 this._onStart = new Roo.util.Event(this);
3356 this.onStart = new Roo.util.Event(this);
3357 this.onTween = new Roo.util.Event(this);
3358 this._onTween = new Roo.util.Event(this);
3359 this.onComplete = new Roo.util.Event(this);
3360 this._onComplete = new Roo.util.Event(this);
3361 this._onStart.addListener(onStart);
3362 this._onTween.addListener(onTween);
3363 this._onComplete.addListener(onComplete);
3368 * Portions of this file are based on pieces of Yahoo User Interface Library
3369 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3370 * YUI licensed under the BSD License:
3371 * http://developer.yahoo.net/yui/license.txt
3372 * <script type="text/javascript">
3376 Roo.lib.AnimMgr = new function() {
3393 this.registerElement = function(tween) {
3394 queue[queue.length] = tween;
3396 tween._onStart.fire();
3401 this.unRegister = function(tween, index) {
3402 tween._onComplete.fire();
3403 index = index || getIndex(tween);
3405 queue.splice(index, 1);
3409 if (tweenCount <= 0) {
3415 this.start = function() {
3416 if (thread === null) {
3417 thread = setInterval(this.run, this.delay);
3422 this.stop = function(tween) {
3424 clearInterval(thread);
3426 for (var i = 0, len = queue.length; i < len; ++i) {
3427 if (queue[0].isAnimated()) {
3428 this.unRegister(queue[0], 0);
3437 this.unRegister(tween);
3442 this.run = function() {
3443 for (var i = 0, len = queue.length; i < len; ++i) {
3444 var tween = queue[i];
3445 if (!tween || !tween.isAnimated()) {
3449 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3451 tween.currentFrame += 1;
3453 if (tween.useSeconds) {
3454 correctFrame(tween);
3456 tween._onTween.fire();
3459 Roo.lib.AnimMgr.stop(tween, i);
3464 var getIndex = function(anim) {
3465 for (var i = 0, len = queue.length; i < len; ++i) {
3466 if (queue[i] == anim) {
3474 var correctFrame = function(tween) {
3475 var frames = tween.totalFrames;
3476 var frame = tween.currentFrame;
3477 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3478 var elapsed = (new Date() - tween.getStartTime());
3481 if (elapsed < tween.duration * 1000) {
3482 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3484 tweak = frames - (frame + 1);
3486 if (tweak > 0 && isFinite(tweak)) {
3487 if (tween.currentFrame + tweak >= frames) {
3488 tweak = frames - (frame + 1);
3491 tween.currentFrame += tweak;
3495 * Portions of this file are based on pieces of Yahoo User Interface Library
3496 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3497 * YUI licensed under the BSD License:
3498 * http://developer.yahoo.net/yui/license.txt
3499 * <script type="text/javascript">
3502 Roo.lib.Bezier = new function() {
3504 this.getPosition = function(points, t) {
3505 var n = points.length;
3508 for (var i = 0; i < n; ++i) {
3509 tmp[i] = [points[i][0], points[i][1]];
3512 for (var j = 1; j < n; ++j) {
3513 for (i = 0; i < n - j; ++i) {
3514 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3515 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3519 return [ tmp[0][0], tmp[0][1] ];
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3532 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3533 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3536 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3538 var fly = Roo.lib.AnimBase.fly;
3540 var superclass = Y.ColorAnim.superclass;
3541 var proto = Y.ColorAnim.prototype;
3543 proto.toString = function() {
3544 var el = this.getEl();
3545 var id = el.id || el.tagName;
3546 return ("ColorAnim " + id);
3549 proto.patterns.color = /color$/i;
3550 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3551 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3552 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3553 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3556 proto.parseColor = function(s) {
3557 if (s.length == 3) {
3561 var c = this.patterns.hex.exec(s);
3562 if (c && c.length == 4) {
3563 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3566 c = this.patterns.rgb.exec(s);
3567 if (c && c.length == 4) {
3568 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3571 c = this.patterns.hex3.exec(s);
3572 if (c && c.length == 4) {
3573 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3578 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3579 proto.getAttribute = function(attr) {
3580 var el = this.getEl();
3581 if (this.patterns.color.test(attr)) {
3582 var val = fly(el).getStyle(attr);
3584 if (this.patterns.transparent.test(val)) {
3585 var parent = el.parentNode;
3586 val = fly(parent).getStyle(attr);
3588 while (parent && this.patterns.transparent.test(val)) {
3589 parent = parent.parentNode;
3590 val = fly(parent).getStyle(attr);
3591 if (parent.tagName.toUpperCase() == 'HTML') {
3597 val = superclass.getAttribute.call(this, attr);
3602 proto.getAttribute = function(attr) {
3603 var el = this.getEl();
3604 if (this.patterns.color.test(attr)) {
3605 var val = fly(el).getStyle(attr);
3607 if (this.patterns.transparent.test(val)) {
3608 var parent = el.parentNode;
3609 val = fly(parent).getStyle(attr);
3611 while (parent && this.patterns.transparent.test(val)) {
3612 parent = parent.parentNode;
3613 val = fly(parent).getStyle(attr);
3614 if (parent.tagName.toUpperCase() == 'HTML') {
3620 val = superclass.getAttribute.call(this, attr);
3626 proto.doMethod = function(attr, start, end) {
3629 if (this.patterns.color.test(attr)) {
3631 for (var i = 0, len = start.length; i < len; ++i) {
3632 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3635 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3638 val = superclass.doMethod.call(this, attr, start, end);
3644 proto.setRuntimeAttribute = function(attr) {
3645 superclass.setRuntimeAttribute.call(this, attr);
3647 if (this.patterns.color.test(attr)) {
3648 var attributes = this.attributes;
3649 var start = this.parseColor(this.runtimeAttributes[attr].start);
3650 var end = this.parseColor(this.runtimeAttributes[attr].end);
3652 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3653 end = this.parseColor(attributes[attr].by);
3655 for (var i = 0, len = start.length; i < len; ++i) {
3656 end[i] = start[i] + end[i];
3660 this.runtimeAttributes[attr].start = start;
3661 this.runtimeAttributes[attr].end = end;
3667 * Portions of this file are based on pieces of Yahoo User Interface Library
3668 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669 * YUI licensed under the BSD License:
3670 * http://developer.yahoo.net/yui/license.txt
3671 * <script type="text/javascript">
3677 easeNone: function (t, b, c, d) {
3678 return c * t / d + b;
3682 easeIn: function (t, b, c, d) {
3683 return c * (t /= d) * t + b;
3687 easeOut: function (t, b, c, d) {
3688 return -c * (t /= d) * (t - 2) + b;
3692 easeBoth: function (t, b, c, d) {
3693 if ((t /= d / 2) < 1) {
3694 return c / 2 * t * t + b;
3697 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3701 easeInStrong: function (t, b, c, d) {
3702 return c * (t /= d) * t * t * t + b;
3706 easeOutStrong: function (t, b, c, d) {
3707 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3711 easeBothStrong: function (t, b, c, d) {
3712 if ((t /= d / 2) < 1) {
3713 return c / 2 * t * t * t * t + b;
3716 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3721 elasticIn: function (t, b, c, d, a, p) {
3725 if ((t /= d) == 1) {
3732 if (!a || a < Math.abs(c)) {
3737 var s = p / (2 * Math.PI) * Math.asin(c / a);
3740 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3744 elasticOut: function (t, b, c, d, a, p) {
3748 if ((t /= d) == 1) {
3755 if (!a || a < Math.abs(c)) {
3760 var s = p / (2 * Math.PI) * Math.asin(c / a);
3763 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3767 elasticBoth: function (t, b, c, d, a, p) {
3772 if ((t /= d / 2) == 2) {
3780 if (!a || a < Math.abs(c)) {
3785 var s = p / (2 * Math.PI) * Math.asin(c / a);
3789 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3790 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3792 return a * Math.pow(2, -10 * (t -= 1)) *
3793 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3798 backIn: function (t, b, c, d, s) {
3799 if (typeof s == 'undefined') {
3802 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3806 backOut: function (t, b, c, d, s) {
3807 if (typeof s == 'undefined') {
3810 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3814 backBoth: function (t, b, c, d, s) {
3815 if (typeof s == 'undefined') {
3819 if ((t /= d / 2 ) < 1) {
3820 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3822 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3826 bounceIn: function (t, b, c, d) {
3827 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3831 bounceOut: function (t, b, c, d) {
3832 if ((t /= d) < (1 / 2.75)) {
3833 return c * (7.5625 * t * t) + b;
3834 } else if (t < (2 / 2.75)) {
3835 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3836 } else if (t < (2.5 / 2.75)) {
3837 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3839 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3843 bounceBoth: function (t, b, c, d) {
3845 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3847 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3850 * Portions of this file are based on pieces of Yahoo User Interface Library
3851 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3852 * YUI licensed under the BSD License:
3853 * http://developer.yahoo.net/yui/license.txt
3854 * <script type="text/javascript">
3858 Roo.lib.Motion = function(el, attributes, duration, method) {
3860 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3864 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3868 var superclass = Y.Motion.superclass;
3869 var proto = Y.Motion.prototype;
3871 proto.toString = function() {
3872 var el = this.getEl();
3873 var id = el.id || el.tagName;
3874 return ("Motion " + id);
3877 proto.patterns.points = /^points$/i;
3879 proto.setAttribute = function(attr, val, unit) {
3880 if (this.patterns.points.test(attr)) {
3881 unit = unit || 'px';
3882 superclass.setAttribute.call(this, 'left', val[0], unit);
3883 superclass.setAttribute.call(this, 'top', val[1], unit);
3885 superclass.setAttribute.call(this, attr, val, unit);
3889 proto.getAttribute = function(attr) {
3890 if (this.patterns.points.test(attr)) {
3892 superclass.getAttribute.call(this, 'left'),
3893 superclass.getAttribute.call(this, 'top')
3896 val = superclass.getAttribute.call(this, attr);
3902 proto.doMethod = function(attr, start, end) {
3905 if (this.patterns.points.test(attr)) {
3906 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3907 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3909 val = superclass.doMethod.call(this, attr, start, end);
3914 proto.setRuntimeAttribute = function(attr) {
3915 if (this.patterns.points.test(attr)) {
3916 var el = this.getEl();
3917 var attributes = this.attributes;
3919 var control = attributes['points']['control'] || [];
3923 if (control.length > 0 && !(control[0] instanceof Array)) {
3924 control = [control];
3927 for (i = 0,len = control.length; i < len; ++i) {
3928 tmp[i] = control[i];
3933 Roo.fly(el).position();
3935 if (isset(attributes['points']['from'])) {
3936 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3939 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3942 start = this.getAttribute('points');
3945 if (isset(attributes['points']['to'])) {
3946 end = translateValues.call(this, attributes['points']['to'], start);
3948 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3949 for (i = 0,len = control.length; i < len; ++i) {
3950 control[i] = translateValues.call(this, control[i], start);
3954 } else if (isset(attributes['points']['by'])) {
3955 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3957 for (i = 0,len = control.length; i < len; ++i) {
3958 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3962 this.runtimeAttributes[attr] = [start];
3964 if (control.length > 0) {
3965 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3968 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3971 superclass.setRuntimeAttribute.call(this, attr);
3975 var translateValues = function(val, start) {
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3982 var isset = function(prop) {
3983 return (typeof prop !== 'undefined');
3987 * Portions of this file are based on pieces of Yahoo User Interface Library
3988 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3989 * YUI licensed under the BSD License:
3990 * http://developer.yahoo.net/yui/license.txt
3991 * <script type="text/javascript">
3995 Roo.lib.Scroll = function(el, attributes, duration, method) {
3997 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4001 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4005 var superclass = Y.Scroll.superclass;
4006 var proto = Y.Scroll.prototype;
4008 proto.toString = function() {
4009 var el = this.getEl();
4010 var id = el.id || el.tagName;
4011 return ("Scroll " + id);
4014 proto.doMethod = function(attr, start, end) {
4017 if (attr == 'scroll') {
4019 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4020 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4024 val = superclass.doMethod.call(this, attr, start, end);
4029 proto.getAttribute = function(attr) {
4031 var el = this.getEl();
4033 if (attr == 'scroll') {
4034 val = [ el.scrollLeft, el.scrollTop ];
4036 val = superclass.getAttribute.call(this, attr);
4042 proto.setAttribute = function(attr, val, unit) {
4043 var el = this.getEl();
4045 if (attr == 'scroll') {
4046 el.scrollLeft = val[0];
4047 el.scrollTop = val[1];
4049 superclass.setAttribute.call(this, attr, val, unit);
4055 * Ext JS Library 1.1.1
4056 * Copyright(c) 2006-2007, Ext JS, LLC.
4058 * Originally Released Under LGPL - original licence link has changed is not relivant.
4061 * <script type="text/javascript">
4065 // nasty IE9 hack - what a pile of crap that is..
4067 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4068 Range.prototype.createContextualFragment = function (html) {
4069 var doc = window.document;
4070 var container = doc.createElement("div");
4071 container.innerHTML = html;
4072 var frag = doc.createDocumentFragment(), n;
4073 while ((n = container.firstChild)) {
4074 frag.appendChild(n);
4081 * @class Roo.DomHelper
4082 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4083 * 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>.
4086 Roo.DomHelper = function(){
4087 var tempTableEl = null;
4088 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4089 var tableRe = /^table|tbody|tr|td$/i;
4091 // build as innerHTML where available
4093 var createHtml = function(o){
4094 if(typeof o == 'string'){
4103 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4104 if(attr == "style"){
4106 if(typeof s == "function"){
4109 if(typeof s == "string"){
4110 b += ' style="' + s + '"';
4111 }else if(typeof s == "object"){
4114 if(typeof s[key] != "function"){
4115 b += key + ":" + s[key] + ";";
4122 b += ' class="' + o["cls"] + '"';
4123 }else if(attr == "htmlFor"){
4124 b += ' for="' + o["htmlFor"] + '"';
4126 b += " " + attr + '="' + o[attr] + '"';
4130 if(emptyTags.test(o.tag)){
4134 var cn = o.children || o.cn;
4136 //http://bugs.kde.org/show_bug.cgi?id=71506
4137 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4138 for(var i = 0, len = cn.length; i < len; i++) {
4139 b += createHtml(cn[i], b);
4142 b += createHtml(cn, b);
4148 b += "</" + o.tag + ">";
4155 var createDom = function(o, parentNode){
4157 // defininition craeted..
4159 if (o.ns && o.ns != 'html') {
4161 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4162 xmlns[o.ns] = o.xmlns;
4165 if (typeof(xmlns[o.ns]) == 'undefined') {
4166 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4172 if (typeof(o) == 'string') {
4173 return parentNode.appendChild(document.createTextNode(o));
4175 o.tag = o.tag || div;
4176 if (o.ns && Roo.isIE) {
4178 o.tag = o.ns + ':' + o.tag;
4181 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4182 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4185 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4186 attr == "style" || typeof o[attr] == "function") continue;
4188 if(attr=="cls" && Roo.isIE){
4189 el.className = o["cls"];
4191 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4192 else el[attr] = o[attr];
4195 Roo.DomHelper.applyStyles(el, o.style);
4196 var cn = o.children || o.cn;
4198 //http://bugs.kde.org/show_bug.cgi?id=71506
4199 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4200 for(var i = 0, len = cn.length; i < len; i++) {
4201 createDom(cn[i], el);
4208 el.innerHTML = o.html;
4211 parentNode.appendChild(el);
4216 var ieTable = function(depth, s, h, e){
4217 tempTableEl.innerHTML = [s, h, e].join('');
4218 var i = -1, el = tempTableEl;
4225 // kill repeat to save bytes
4229 tbe = '</tbody>'+te,
4235 * Nasty code for IE's broken table implementation
4237 var insertIntoTable = function(tag, where, el, html){
4239 tempTableEl = document.createElement('div');
4244 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4247 if(where == 'beforebegin'){
4251 before = el.nextSibling;
4254 node = ieTable(4, trs, html, tre);
4256 else if(tag == 'tr'){
4257 if(where == 'beforebegin'){
4260 node = ieTable(3, tbs, html, tbe);
4261 } else if(where == 'afterend'){
4262 before = el.nextSibling;
4264 node = ieTable(3, tbs, html, tbe);
4265 } else{ // INTO a TR
4266 if(where == 'afterbegin'){
4267 before = el.firstChild;
4269 node = ieTable(4, trs, html, tre);
4271 } else if(tag == 'tbody'){
4272 if(where == 'beforebegin'){
4275 node = ieTable(2, ts, html, te);
4276 } else if(where == 'afterend'){
4277 before = el.nextSibling;
4279 node = ieTable(2, ts, html, te);
4281 if(where == 'afterbegin'){
4282 before = el.firstChild;
4284 node = ieTable(3, tbs, html, tbe);
4287 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4290 if(where == 'afterbegin'){
4291 before = el.firstChild;
4293 node = ieTable(2, ts, html, te);
4295 el.insertBefore(node, before);
4300 /** True to force the use of DOM instead of html fragments @type Boolean */
4304 * Returns the markup for the passed Element(s) config
4305 * @param {Object} o The Dom object spec (and children)
4308 markup : function(o){
4309 return createHtml(o);
4313 * Applies a style specification to an element
4314 * @param {String/HTMLElement} el The element to apply styles to
4315 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4316 * a function which returns such a specification.
4318 applyStyles : function(el, styles){
4321 if(typeof styles == "string"){
4322 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4324 while ((matches = re.exec(styles)) != null){
4325 el.setStyle(matches[1], matches[2]);
4327 }else if (typeof styles == "object"){
4328 for (var style in styles){
4329 el.setStyle(style, styles[style]);
4331 }else if (typeof styles == "function"){
4332 Roo.DomHelper.applyStyles(el, styles.call());
4338 * Inserts an HTML fragment into the Dom
4339 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4340 * @param {HTMLElement} el The context element
4341 * @param {String} html The HTML fragmenet
4342 * @return {HTMLElement} The new node
4344 insertHtml : function(where, el, html){
4345 where = where.toLowerCase();
4346 if(el.insertAdjacentHTML){
4347 if(tableRe.test(el.tagName)){
4349 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4355 el.insertAdjacentHTML('BeforeBegin', html);
4356 return el.previousSibling;
4358 el.insertAdjacentHTML('AfterBegin', html);
4359 return el.firstChild;
4361 el.insertAdjacentHTML('BeforeEnd', html);
4362 return el.lastChild;
4364 el.insertAdjacentHTML('AfterEnd', html);
4365 return el.nextSibling;
4367 throw 'Illegal insertion point -> "' + where + '"';
4369 var range = el.ownerDocument.createRange();
4373 range.setStartBefore(el);
4374 frag = range.createContextualFragment(html);
4375 el.parentNode.insertBefore(frag, el);
4376 return el.previousSibling;
4379 range.setStartBefore(el.firstChild);
4380 frag = range.createContextualFragment(html);
4381 el.insertBefore(frag, el.firstChild);
4382 return el.firstChild;
4384 el.innerHTML = html;
4385 return el.firstChild;
4389 range.setStartAfter(el.lastChild);
4390 frag = range.createContextualFragment(html);
4391 el.appendChild(frag);
4392 return el.lastChild;
4394 el.innerHTML = html;
4395 return el.lastChild;
4398 range.setStartAfter(el);
4399 frag = range.createContextualFragment(html);
4400 el.parentNode.insertBefore(frag, el.nextSibling);
4401 return el.nextSibling;
4403 throw 'Illegal insertion point -> "' + where + '"';
4407 * Creates new Dom element(s) and inserts them before el
4408 * @param {String/HTMLElement/Element} el The context element
4409 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4410 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4411 * @return {HTMLElement/Roo.Element} The new node
4413 insertBefore : function(el, o, returnElement){
4414 return this.doInsert(el, o, returnElement, "beforeBegin");
4418 * Creates new Dom element(s) and inserts them after el
4419 * @param {String/HTMLElement/Element} el The context element
4420 * @param {Object} o The Dom object spec (and children)
4421 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4422 * @return {HTMLElement/Roo.Element} The new node
4424 insertAfter : function(el, o, returnElement){
4425 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4429 * Creates new Dom element(s) and inserts them as the first child of el
4430 * @param {String/HTMLElement/Element} el The context element
4431 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4432 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4433 * @return {HTMLElement/Roo.Element} The new node
4435 insertFirst : function(el, o, returnElement){
4436 return this.doInsert(el, o, returnElement, "afterBegin");
4440 doInsert : function(el, o, returnElement, pos, sibling){
4441 el = Roo.getDom(el);
4443 if(this.useDom || o.ns){
4444 newNode = createDom(o, null);
4445 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4447 var html = createHtml(o);
4448 newNode = this.insertHtml(pos, el, html);
4450 return returnElement ? Roo.get(newNode, true) : newNode;
4454 * Creates new Dom element(s) and appends them to el
4455 * @param {String/HTMLElement/Element} el The context element
4456 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4457 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4458 * @return {HTMLElement/Roo.Element} The new node
4460 append : function(el, o, returnElement){
4461 el = Roo.getDom(el);
4463 if(this.useDom || o.ns){
4464 newNode = createDom(o, null);
4465 el.appendChild(newNode);
4467 var html = createHtml(o);
4468 newNode = this.insertHtml("beforeEnd", el, html);
4470 return returnElement ? Roo.get(newNode, true) : newNode;
4474 * Creates new Dom element(s) and overwrites the contents of el with them
4475 * @param {String/HTMLElement/Element} el The context element
4476 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4477 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4478 * @return {HTMLElement/Roo.Element} The new node
4480 overwrite : function(el, o, returnElement){
4481 el = Roo.getDom(el);
4484 while (el.childNodes.length) {
4485 el.removeChild(el.firstChild);
4489 el.innerHTML = createHtml(o);
4492 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4496 * Creates a new Roo.DomHelper.Template from the Dom object spec
4497 * @param {Object} o The Dom object spec (and children)
4498 * @return {Roo.DomHelper.Template} The new template
4500 createTemplate : function(o){
4501 var html = createHtml(o);
4502 return new Roo.Template(html);
4508 * Ext JS Library 1.1.1
4509 * Copyright(c) 2006-2007, Ext JS, LLC.
4511 * Originally Released Under LGPL - original licence link has changed is not relivant.
4514 * <script type="text/javascript">
4518 * @class Roo.Template
4519 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4520 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4523 var t = new Roo.Template({
4524 html : '<div name="{id}">' +
4525 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4527 myformat: function (value, allValues) {
4528 return 'XX' + value;
4531 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4533 * For more information see this blog post with examples:
4534 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4535 - Create Elements using DOM, HTML fragments and Templates</a>.
4537 * @param {Object} cfg - Configuration object.
4539 Roo.Template = function(cfg){
4541 if(cfg instanceof Array){
4543 }else if(arguments.length > 1){
4544 cfg = Array.prototype.join.call(arguments, "");
4548 if (typeof(cfg) == 'object') {
4559 Roo.Template.prototype = {
4562 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4563 * it should be fixed so that template is observable...
4567 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4571 * Returns an HTML fragment of this template with the specified values applied.
4572 * @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'})
4573 * @return {String} The HTML fragment
4575 applyTemplate : function(values){
4579 return this.compiled(values);
4581 var useF = this.disableFormats !== true;
4582 var fm = Roo.util.Format, tpl = this;
4583 var fn = function(m, name, format, args){
4585 if(format.substr(0, 5) == "this."){
4586 return tpl.call(format.substr(5), values[name], values);
4589 // quoted values are required for strings in compiled templates,
4590 // but for non compiled we need to strip them
4591 // quoted reversed for jsmin
4592 var re = /^\s*['"](.*)["']\s*$/;
4593 args = args.split(',');
4594 for(var i = 0, len = args.length; i < len; i++){
4595 args[i] = args[i].replace(re, "$1");
4597 args = [values[name]].concat(args);
4599 args = [values[name]];
4601 return fm[format].apply(fm, args);
4604 return values[name] !== undefined ? values[name] : "";
4607 return this.html.replace(this.re, fn);
4625 this.loading = true;
4626 this.compiled = false;
4628 var cx = new Roo.data.Connection();
4632 success : function (response) {
4634 _t.html = response.responseText;
4638 failure : function(response) {
4639 Roo.log("Template failed to load from " + url);
4646 * Sets the HTML used as the template and optionally compiles it.
4647 * @param {String} html
4648 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4649 * @return {Roo.Template} this
4651 set : function(html, compile){
4653 this.compiled = null;
4661 * True to disable format functions (defaults to false)
4664 disableFormats : false,
4667 * The regular expression used to match template variables
4671 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4674 * Compiles the template into an internal function, eliminating the RegEx overhead.
4675 * @return {Roo.Template} this
4677 compile : function(){
4678 var fm = Roo.util.Format;
4679 var useF = this.disableFormats !== true;
4680 var sep = Roo.isGecko ? "+" : ",";
4681 var fn = function(m, name, format, args){
4683 args = args ? ',' + args : "";
4684 if(format.substr(0, 5) != "this."){
4685 format = "fm." + format + '(';
4687 format = 'this.call("'+ format.substr(5) + '", ';
4691 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4693 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4696 // branched to use + in gecko and [].join() in others
4698 body = "this.compiled = function(values){ return '" +
4699 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4702 body = ["this.compiled = function(values){ return ['"];
4703 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4704 body.push("'].join('');};");
4705 body = body.join('');
4715 // private function used to call members
4716 call : function(fnName, value, allValues){
4717 return this[fnName](value, allValues);
4721 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4722 * @param {String/HTMLElement/Roo.Element} el The context element
4723 * @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'})
4724 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4725 * @return {HTMLElement/Roo.Element} The new node or Element
4727 insertFirst: function(el, values, returnElement){
4728 return this.doInsert('afterBegin', el, values, returnElement);
4732 * Applies the supplied values to the template and inserts the new node(s) before el.
4733 * @param {String/HTMLElement/Roo.Element} el The context element
4734 * @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'})
4735 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4736 * @return {HTMLElement/Roo.Element} The new node or Element
4738 insertBefore: function(el, values, returnElement){
4739 return this.doInsert('beforeBegin', el, values, returnElement);
4743 * Applies the supplied values to the template and inserts the new node(s) after el.
4744 * @param {String/HTMLElement/Roo.Element} el The context element
4745 * @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'})
4746 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4747 * @return {HTMLElement/Roo.Element} The new node or Element
4749 insertAfter : function(el, values, returnElement){
4750 return this.doInsert('afterEnd', el, values, returnElement);
4754 * Applies the supplied values to the template and appends the new node(s) to el.
4755 * @param {String/HTMLElement/Roo.Element} el The context element
4756 * @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'})
4757 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4758 * @return {HTMLElement/Roo.Element} The new node or Element
4760 append : function(el, values, returnElement){
4761 return this.doInsert('beforeEnd', el, values, returnElement);
4764 doInsert : function(where, el, values, returnEl){
4765 el = Roo.getDom(el);
4766 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4767 return returnEl ? Roo.get(newNode, true) : newNode;
4771 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 overwrite : function(el, values, returnElement){
4778 el = Roo.getDom(el);
4779 el.innerHTML = this.applyTemplate(values);
4780 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4784 * Alias for {@link #applyTemplate}
4787 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4790 Roo.DomHelper.Template = Roo.Template;
4793 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4794 * @param {String/HTMLElement} el A DOM element or its id
4795 * @returns {Roo.Template} The created template
4798 Roo.Template.from = function(el){
4799 el = Roo.getDom(el);
4800 return new Roo.Template(el.value || el.innerHTML);
4803 * Ext JS Library 1.1.1
4804 * Copyright(c) 2006-2007, Ext JS, LLC.
4806 * Originally Released Under LGPL - original licence link has changed is not relivant.
4809 * <script type="text/javascript">
4814 * This is code is also distributed under MIT license for use
4815 * with jQuery and prototype JavaScript libraries.
4818 * @class Roo.DomQuery
4819 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).
4821 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>
4824 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.
4826 <h4>Element Selectors:</h4>
4828 <li> <b>*</b> any element</li>
4829 <li> <b>E</b> an element with the tag E</li>
4830 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4831 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4832 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4833 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4835 <h4>Attribute Selectors:</h4>
4836 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4838 <li> <b>E[foo]</b> has an attribute "foo"</li>
4839 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4840 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4841 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4842 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4843 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4844 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4846 <h4>Pseudo Classes:</h4>
4848 <li> <b>E:first-child</b> E is the first child of its parent</li>
4849 <li> <b>E:last-child</b> E is the last child of its parent</li>
4850 <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>
4851 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4852 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4853 <li> <b>E:only-child</b> E is the only child of its parent</li>
4854 <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>
4855 <li> <b>E:first</b> the first E in the resultset</li>
4856 <li> <b>E:last</b> the last E in the resultset</li>
4857 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4858 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4859 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4860 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4861 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4862 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4863 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4864 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4865 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4867 <h4>CSS Value Selectors:</h4>
4869 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4870 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4871 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4872 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4873 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4874 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4878 Roo.DomQuery = function(){
4879 var cache = {}, simpleCache = {}, valueCache = {};
4880 var nonSpace = /\S/;
4881 var trimRe = /^\s+|\s+$/g;
4882 var tplRe = /\{(\d+)\}/g;
4883 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4884 var tagTokenRe = /^(#)?([\w-\*]+)/;
4885 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4887 function child(p, index){
4889 var n = p.firstChild;
4891 if(n.nodeType == 1){
4902 while((n = n.nextSibling) && n.nodeType != 1);
4907 while((n = n.previousSibling) && n.nodeType != 1);
4911 function children(d){
4912 var n = d.firstChild, ni = -1;
4914 var nx = n.nextSibling;
4915 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4925 function byClassName(c, a, v){
4929 var r = [], ri = -1, cn;
4930 for(var i = 0, ci; ci = c[i]; i++){
4931 if((' '+ci.className+' ').indexOf(v) != -1){
4938 function attrValue(n, attr){
4939 if(!n.tagName && typeof n.length != "undefined"){
4948 if(attr == "class" || attr == "className"){
4951 return n.getAttribute(attr) || n[attr];
4955 function getNodes(ns, mode, tagName){
4956 var result = [], ri = -1, cs;
4960 tagName = tagName || "*";
4961 if(typeof ns.getElementsByTagName != "undefined"){
4965 for(var i = 0, ni; ni = ns[i]; i++){
4966 cs = ni.getElementsByTagName(tagName);
4967 for(var j = 0, ci; ci = cs[j]; j++){
4971 }else if(mode == "/" || mode == ">"){
4972 var utag = tagName.toUpperCase();
4973 for(var i = 0, ni, cn; ni = ns[i]; i++){
4974 cn = ni.children || ni.childNodes;
4975 for(var j = 0, cj; cj = cn[j]; j++){
4976 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4981 }else if(mode == "+"){
4982 var utag = tagName.toUpperCase();
4983 for(var i = 0, n; n = ns[i]; i++){
4984 while((n = n.nextSibling) && n.nodeType != 1);
4985 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4989 }else if(mode == "~"){
4990 for(var i = 0, n; n = ns[i]; i++){
4991 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5000 function concat(a, b){
5004 for(var i = 0, l = b.length; i < l; i++){
5010 function byTag(cs, tagName){
5011 if(cs.tagName || cs == document){
5017 var r = [], ri = -1;
5018 tagName = tagName.toLowerCase();
5019 for(var i = 0, ci; ci = cs[i]; i++){
5020 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5027 function byId(cs, attr, id){
5028 if(cs.tagName || cs == document){
5034 var r = [], ri = -1;
5035 for(var i = 0,ci; ci = cs[i]; i++){
5036 if(ci && ci.id == id){
5044 function byAttribute(cs, attr, value, op, custom){
5045 var r = [], ri = -1, st = custom=="{";
5046 var f = Roo.DomQuery.operators[op];
5047 for(var i = 0, ci; ci = cs[i]; i++){
5050 a = Roo.DomQuery.getStyle(ci, attr);
5052 else if(attr == "class" || attr == "className"){
5054 }else if(attr == "for"){
5056 }else if(attr == "href"){
5057 a = ci.getAttribute("href", 2);
5059 a = ci.getAttribute(attr);
5061 if((f && f(a, value)) || (!f && a)){
5068 function byPseudo(cs, name, value){
5069 return Roo.DomQuery.pseudos[name](cs, value);
5072 // This is for IE MSXML which does not support expandos.
5073 // IE runs the same speed using setAttribute, however FF slows way down
5074 // and Safari completely fails so they need to continue to use expandos.
5075 var isIE = window.ActiveXObject ? true : false;
5077 // this eval is stop the compressor from
5078 // renaming the variable to something shorter
5080 /** eval:var:batch */
5085 function nodupIEXml(cs){
5087 cs[0].setAttribute("_nodup", d);
5089 for(var i = 1, len = cs.length; i < len; i++){
5091 if(!c.getAttribute("_nodup") != d){
5092 c.setAttribute("_nodup", d);
5096 for(var i = 0, len = cs.length; i < len; i++){
5097 cs[i].removeAttribute("_nodup");
5106 var len = cs.length, c, i, r = cs, cj, ri = -1;
5107 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5110 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5111 return nodupIEXml(cs);
5115 for(i = 1; c = cs[i]; i++){
5120 for(var j = 0; j < i; j++){
5123 for(j = i+1; cj = cs[j]; j++){
5135 function quickDiffIEXml(c1, c2){
5137 for(var i = 0, len = c1.length; i < len; i++){
5138 c1[i].setAttribute("_qdiff", d);
5141 for(var i = 0, len = c2.length; i < len; i++){
5142 if(c2[i].getAttribute("_qdiff") != d){
5143 r[r.length] = c2[i];
5146 for(var i = 0, len = c1.length; i < len; i++){
5147 c1[i].removeAttribute("_qdiff");
5152 function quickDiff(c1, c2){
5153 var len1 = c1.length;
5157 if(isIE && c1[0].selectSingleNode){
5158 return quickDiffIEXml(c1, c2);
5161 for(var i = 0; i < len1; i++){
5165 for(var i = 0, len = c2.length; i < len; i++){
5166 if(c2[i]._qdiff != d){
5167 r[r.length] = c2[i];
5173 function quickId(ns, mode, root, id){
5175 var d = root.ownerDocument || root;
5176 return d.getElementById(id);
5178 ns = getNodes(ns, mode, "*");
5179 return byId(ns, null, id);
5183 getStyle : function(el, name){
5184 return Roo.fly(el).getStyle(name);
5187 * Compiles a selector/xpath query into a reusable function. The returned function
5188 * takes one parameter "root" (optional), which is the context node from where the query should start.
5189 * @param {String} selector The selector/xpath query
5190 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5191 * @return {Function}
5193 compile : function(path, type){
5194 type = type || "select";
5196 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5197 var q = path, mode, lq;
5198 var tk = Roo.DomQuery.matchers;
5199 var tklen = tk.length;
5202 // accept leading mode switch
5203 var lmode = q.match(modeRe);
5204 if(lmode && lmode[1]){
5205 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5206 q = q.replace(lmode[1], "");
5208 // strip leading slashes
5209 while(path.substr(0, 1)=="/"){
5210 path = path.substr(1);
5213 while(q && lq != q){
5215 var tm = q.match(tagTokenRe);
5216 if(type == "select"){
5219 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5221 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5223 q = q.replace(tm[0], "");
5224 }else if(q.substr(0, 1) != '@'){
5225 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5230 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5232 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5234 q = q.replace(tm[0], "");
5237 while(!(mm = q.match(modeRe))){
5238 var matched = false;
5239 for(var j = 0; j < tklen; j++){
5241 var m = q.match(t.re);
5243 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5246 q = q.replace(m[0], "");
5251 // prevent infinite loop on bad selector
5253 throw 'Error parsing selector, parsing failed at "' + q + '"';
5257 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5258 q = q.replace(mm[1], "");
5261 fn[fn.length] = "return nodup(n);\n}";
5264 * list of variables that need from compression as they are used by eval.
5274 * eval:var:byClassName
5276 * eval:var:byAttribute
5277 * eval:var:attrValue
5285 * Selects a group of elements.
5286 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5287 * @param {Node} root (optional) The start of the query (defaults to document).
5290 select : function(path, root, type){
5291 if(!root || root == document){
5294 if(typeof root == "string"){
5295 root = document.getElementById(root);
5297 var paths = path.split(",");
5299 for(var i = 0, len = paths.length; i < len; i++){
5300 var p = paths[i].replace(trimRe, "");
5302 cache[p] = Roo.DomQuery.compile(p);
5304 throw p + " is not a valid selector";
5307 var result = cache[p](root);
5308 if(result && result != document){
5309 results = results.concat(result);
5312 if(paths.length > 1){
5313 return nodup(results);
5319 * Selects a single element.
5320 * @param {String} selector The selector/xpath query
5321 * @param {Node} root (optional) The start of the query (defaults to document).
5324 selectNode : function(path, root){
5325 return Roo.DomQuery.select(path, root)[0];
5329 * Selects the value of a node, optionally replacing null with the defaultValue.
5330 * @param {String} selector The selector/xpath query
5331 * @param {Node} root (optional) The start of the query (defaults to document).
5332 * @param {String} defaultValue
5334 selectValue : function(path, root, defaultValue){
5335 path = path.replace(trimRe, "");
5336 if(!valueCache[path]){
5337 valueCache[path] = Roo.DomQuery.compile(path, "select");
5339 var n = valueCache[path](root);
5340 n = n[0] ? n[0] : n;
5341 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5342 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5346 * Selects the value of a node, parsing integers and floats.
5347 * @param {String} selector The selector/xpath query
5348 * @param {Node} root (optional) The start of the query (defaults to document).
5349 * @param {Number} defaultValue
5352 selectNumber : function(path, root, defaultValue){
5353 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5354 return parseFloat(v);
5358 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5359 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5360 * @param {String} selector The simple selector to test
5363 is : function(el, ss){
5364 if(typeof el == "string"){
5365 el = document.getElementById(el);
5367 var isArray = (el instanceof Array);
5368 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5369 return isArray ? (result.length == el.length) : (result.length > 0);
5373 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5374 * @param {Array} el An array of elements to filter
5375 * @param {String} selector The simple selector to test
5376 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5377 * the selector instead of the ones that match
5380 filter : function(els, ss, nonMatches){
5381 ss = ss.replace(trimRe, "");
5382 if(!simpleCache[ss]){
5383 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5385 var result = simpleCache[ss](els);
5386 return nonMatches ? quickDiff(result, els) : result;
5390 * Collection of matching regular expressions and code snippets.
5394 select: 'n = byClassName(n, null, " {1} ");'
5396 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5397 select: 'n = byPseudo(n, "{1}", "{2}");'
5399 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5400 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5403 select: 'n = byId(n, null, "{1}");'
5406 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5411 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5412 * 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, > <.
5415 "=" : function(a, v){
5418 "!=" : function(a, v){
5421 "^=" : function(a, v){
5422 return a && a.substr(0, v.length) == v;
5424 "$=" : function(a, v){
5425 return a && a.substr(a.length-v.length) == v;
5427 "*=" : function(a, v){
5428 return a && a.indexOf(v) !== -1;
5430 "%=" : function(a, v){
5431 return (a % v) == 0;
5433 "|=" : function(a, v){
5434 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5436 "~=" : function(a, v){
5437 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5442 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5443 * and the argument (if any) supplied in the selector.
5446 "first-child" : function(c){
5447 var r = [], ri = -1, n;
5448 for(var i = 0, ci; ci = n = c[i]; i++){
5449 while((n = n.previousSibling) && n.nodeType != 1);
5457 "last-child" : function(c){
5458 var r = [], ri = -1, n;
5459 for(var i = 0, ci; ci = n = c[i]; i++){
5460 while((n = n.nextSibling) && n.nodeType != 1);
5468 "nth-child" : function(c, a) {
5469 var r = [], ri = -1;
5470 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5471 var f = (m[1] || 1) - 0, l = m[2] - 0;
5472 for(var i = 0, n; n = c[i]; i++){
5473 var pn = n.parentNode;
5474 if (batch != pn._batch) {
5476 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5477 if(cn.nodeType == 1){
5484 if (l == 0 || n.nodeIndex == l){
5487 } else if ((n.nodeIndex + l) % f == 0){
5495 "only-child" : function(c){
5496 var r = [], ri = -1;;
5497 for(var i = 0, ci; ci = c[i]; i++){
5498 if(!prev(ci) && !next(ci)){
5505 "empty" : function(c){
5506 var r = [], ri = -1;
5507 for(var i = 0, ci; ci = c[i]; i++){
5508 var cns = ci.childNodes, j = 0, cn, empty = true;
5511 if(cn.nodeType == 1 || cn.nodeType == 3){
5523 "contains" : function(c, v){
5524 var r = [], ri = -1;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5533 "nodeValue" : function(c, v){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 if(ci.firstChild && ci.firstChild.nodeValue == v){
5543 "checked" : function(c){
5544 var r = [], ri = -1;
5545 for(var i = 0, ci; ci = c[i]; i++){
5546 if(ci.checked == true){
5553 "not" : function(c, ss){
5554 return Roo.DomQuery.filter(c, ss, true);
5557 "odd" : function(c){
5558 return this["nth-child"](c, "odd");
5561 "even" : function(c){
5562 return this["nth-child"](c, "even");
5565 "nth" : function(c, a){
5566 return c[a-1] || [];
5569 "first" : function(c){
5573 "last" : function(c){
5574 return c[c.length-1] || [];
5577 "has" : function(c, ss){
5578 var s = Roo.DomQuery.select;
5579 var r = [], ri = -1;
5580 for(var i = 0, ci; ci = c[i]; i++){
5581 if(s(ss, ci).length > 0){
5588 "next" : function(c, ss){
5589 var is = Roo.DomQuery.is;
5590 var r = [], ri = -1;
5591 for(var i = 0, ci; ci = c[i]; i++){
5600 "prev" : function(c, ss){
5601 var is = Roo.DomQuery.is;
5602 var r = [], ri = -1;
5603 for(var i = 0, ci; ci = c[i]; i++){
5616 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5617 * @param {String} path The selector/xpath query
5618 * @param {Node} root (optional) The start of the query (defaults to document).
5623 Roo.query = Roo.DomQuery.select;
5626 * Ext JS Library 1.1.1
5627 * Copyright(c) 2006-2007, Ext JS, LLC.
5629 * Originally Released Under LGPL - original licence link has changed is not relivant.
5632 * <script type="text/javascript">
5636 * @class Roo.util.Observable
5637 * Base class that provides a common interface for publishing events. Subclasses are expected to
5638 * to have a property "events" with all the events defined.<br>
5641 Employee = function(name){
5648 Roo.extend(Employee, Roo.util.Observable);
5650 * @param {Object} config properties to use (incuding events / listeners)
5653 Roo.util.Observable = function(cfg){
5656 this.addEvents(cfg.events || {});
5658 delete cfg.events; // make sure
5661 Roo.apply(this, cfg);
5664 this.on(this.listeners);
5665 delete this.listeners;
5668 Roo.util.Observable.prototype = {
5670 * @cfg {Object} listeners list of events and functions to call for this object,
5674 'click' : function(e) {
5684 * Fires the specified event with the passed parameters (minus the event name).
5685 * @param {String} eventName
5686 * @param {Object...} args Variable number of parameters are passed to handlers
5687 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5689 fireEvent : function(){
5690 var ce = this.events[arguments[0].toLowerCase()];
5691 if(typeof ce == "object"){
5692 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5699 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5702 * Appends an event handler to this component
5703 * @param {String} eventName The type of event to listen for
5704 * @param {Function} handler The method the event invokes
5705 * @param {Object} scope (optional) The scope in which to execute the handler
5706 * function. The handler function's "this" context.
5707 * @param {Object} options (optional) An object containing handler configuration
5708 * properties. This may contain any of the following properties:<ul>
5709 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5710 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5711 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5712 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5713 * by the specified number of milliseconds. If the event fires again within that time, the original
5714 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5717 * <b>Combining Options</b><br>
5718 * Using the options argument, it is possible to combine different types of listeners:<br>
5720 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5722 el.on('click', this.onClick, this, {
5729 * <b>Attaching multiple handlers in 1 call</b><br>
5730 * The method also allows for a single argument to be passed which is a config object containing properties
5731 * which specify multiple handlers.
5740 fn: this.onMouseOver,
5744 fn: this.onMouseOut,
5750 * Or a shorthand syntax which passes the same scope object to all handlers:
5753 'click': this.onClick,
5754 'mouseover': this.onMouseOver,
5755 'mouseout': this.onMouseOut,
5760 addListener : function(eventName, fn, scope, o){
5761 if(typeof eventName == "object"){
5764 if(this.filterOptRe.test(e)){
5767 if(typeof o[e] == "function"){
5769 this.addListener(e, o[e], o.scope, o);
5771 // individual options
5772 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5777 o = (!o || typeof o == "boolean") ? {} : o;
5778 eventName = eventName.toLowerCase();
5779 var ce = this.events[eventName] || true;
5780 if(typeof ce == "boolean"){
5781 ce = new Roo.util.Event(this, eventName);
5782 this.events[eventName] = ce;
5784 ce.addListener(fn, scope, o);
5788 * Removes a listener
5789 * @param {String} eventName The type of event to listen for
5790 * @param {Function} handler The handler to remove
5791 * @param {Object} scope (optional) The scope (this object) for the handler
5793 removeListener : function(eventName, fn, scope){
5794 var ce = this.events[eventName.toLowerCase()];
5795 if(typeof ce == "object"){
5796 ce.removeListener(fn, scope);
5801 * Removes all listeners for this object
5803 purgeListeners : function(){
5804 for(var evt in this.events){
5805 if(typeof this.events[evt] == "object"){
5806 this.events[evt].clearListeners();
5811 relayEvents : function(o, events){
5812 var createHandler = function(ename){
5814 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5817 for(var i = 0, len = events.length; i < len; i++){
5818 var ename = events[i];
5819 if(!this.events[ename]){ this.events[ename] = true; };
5820 o.on(ename, createHandler(ename), this);
5825 * Used to define events on this Observable
5826 * @param {Object} object The object with the events defined
5828 addEvents : function(o){
5832 Roo.applyIf(this.events, o);
5836 * Checks to see if this object has any listeners for a specified event
5837 * @param {String} eventName The name of the event to check for
5838 * @return {Boolean} True if the event is being listened for, else false
5840 hasListener : function(eventName){
5841 var e = this.events[eventName];
5842 return typeof e == "object" && e.listeners.length > 0;
5846 * Appends an event handler to this element (shorthand for addListener)
5847 * @param {String} eventName The type of event to listen for
5848 * @param {Function} handler The method the event invokes
5849 * @param {Object} scope (optional) The scope in which to execute the handler
5850 * function. The handler function's "this" context.
5851 * @param {Object} options (optional)
5854 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5856 * Removes a listener (shorthand for removeListener)
5857 * @param {String} eventName The type of event to listen for
5858 * @param {Function} handler The handler to remove
5859 * @param {Object} scope (optional) The scope (this object) for the handler
5862 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5865 * Starts capture on the specified Observable. All events will be passed
5866 * to the supplied function with the event name + standard signature of the event
5867 * <b>before</b> the event is fired. If the supplied function returns false,
5868 * the event will not fire.
5869 * @param {Observable} o The Observable to capture
5870 * @param {Function} fn The function to call
5871 * @param {Object} scope (optional) The scope (this object) for the fn
5874 Roo.util.Observable.capture = function(o, fn, scope){
5875 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5879 * Removes <b>all</b> added captures from the Observable.
5880 * @param {Observable} o The Observable to release
5883 Roo.util.Observable.releaseCapture = function(o){
5884 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5889 var createBuffered = function(h, o, scope){
5890 var task = new Roo.util.DelayedTask();
5892 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5896 var createSingle = function(h, e, fn, scope){
5898 e.removeListener(fn, scope);
5899 return h.apply(scope, arguments);
5903 var createDelayed = function(h, o, scope){
5905 var args = Array.prototype.slice.call(arguments, 0);
5906 setTimeout(function(){
5907 h.apply(scope, args);
5912 Roo.util.Event = function(obj, name){
5915 this.listeners = [];
5918 Roo.util.Event.prototype = {
5919 addListener : function(fn, scope, options){
5920 var o = options || {};
5921 scope = scope || this.obj;
5922 if(!this.isListening(fn, scope)){
5923 var l = {fn: fn, scope: scope, options: o};
5926 h = createDelayed(h, o, scope);
5929 h = createSingle(h, this, fn, scope);
5932 h = createBuffered(h, o, scope);
5935 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5936 this.listeners.push(l);
5938 this.listeners = this.listeners.slice(0);
5939 this.listeners.push(l);
5944 findListener : function(fn, scope){
5945 scope = scope || this.obj;
5946 var ls = this.listeners;
5947 for(var i = 0, len = ls.length; i < len; i++){
5949 if(l.fn == fn && l.scope == scope){
5956 isListening : function(fn, scope){
5957 return this.findListener(fn, scope) != -1;
5960 removeListener : function(fn, scope){
5962 if((index = this.findListener(fn, scope)) != -1){
5964 this.listeners.splice(index, 1);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.splice(index, 1);
5974 clearListeners : function(){
5975 this.listeners = [];
5979 var ls = this.listeners, scope, len = ls.length;
5982 var args = Array.prototype.slice.call(arguments, 0);
5983 for(var i = 0; i < len; i++){
5985 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5986 this.firing = false;
5990 this.firing = false;
5997 * Ext JS Library 1.1.1
5998 * Copyright(c) 2006-2007, Ext JS, LLC.
6000 * Originally Released Under LGPL - original licence link has changed is not relivant.
6003 * <script type="text/javascript">
6007 * @class Roo.EventManager
6008 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6009 * several useful events directly.
6010 * See {@link Roo.EventObject} for more details on normalized event objects.
6013 Roo.EventManager = function(){
6014 var docReadyEvent, docReadyProcId, docReadyState = false;
6015 var resizeEvent, resizeTask, textEvent, textSize;
6016 var E = Roo.lib.Event;
6017 var D = Roo.lib.Dom;
6020 var fireDocReady = function(){
6022 docReadyState = true;
6025 clearInterval(docReadyProcId);
6027 if(Roo.isGecko || Roo.isOpera) {
6028 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6031 var defer = document.getElementById("ie-deferred-loader");
6033 defer.onreadystatechange = null;
6034 defer.parentNode.removeChild(defer);
6038 docReadyEvent.fire();
6039 docReadyEvent.clearListeners();
6044 var initDocReady = function(){
6045 docReadyEvent = new Roo.util.Event();
6046 if(Roo.isGecko || Roo.isOpera) {
6047 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6049 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6050 var defer = document.getElementById("ie-deferred-loader");
6051 defer.onreadystatechange = function(){
6052 if(this.readyState == "complete"){
6056 }else if(Roo.isSafari){
6057 docReadyProcId = setInterval(function(){
6058 var rs = document.readyState;
6059 if(rs == "complete") {
6064 // no matter what, make sure it fires on load
6065 E.on(window, "load", fireDocReady);
6068 var createBuffered = function(h, o){
6069 var task = new Roo.util.DelayedTask(h);
6071 // create new event object impl so new events don't wipe out properties
6072 e = new Roo.EventObjectImpl(e);
6073 task.delay(o.buffer, h, null, [e]);
6077 var createSingle = function(h, el, ename, fn){
6079 Roo.EventManager.removeListener(el, ename, fn);
6084 var createDelayed = function(h, o){
6086 // create new event object impl so new events don't wipe out properties
6087 e = new Roo.EventObjectImpl(e);
6088 setTimeout(function(){
6094 var listen = function(element, ename, opt, fn, scope){
6095 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6096 fn = fn || o.fn; scope = scope || o.scope;
6097 var el = Roo.getDom(element);
6099 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6101 var h = function(e){
6102 e = Roo.EventObject.setEvent(e);
6105 t = e.getTarget(o.delegate, el);
6112 if(o.stopEvent === true){
6115 if(o.preventDefault === true){
6118 if(o.stopPropagation === true){
6119 e.stopPropagation();
6122 if(o.normalized === false){
6126 fn.call(scope || el, e, t, o);
6129 h = createDelayed(h, o);
6132 h = createSingle(h, el, ename, fn);
6135 h = createBuffered(h, o);
6137 fn._handlers = fn._handlers || [];
6138 fn._handlers.push([Roo.id(el), ename, h]);
6141 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6142 el.addEventListener("DOMMouseScroll", h, false);
6143 E.on(window, 'unload', function(){
6144 el.removeEventListener("DOMMouseScroll", h, false);
6147 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6148 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6153 var stopListening = function(el, ename, fn){
6154 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6156 for(var i = 0, len = hds.length; i < len; i++){
6158 if(h[0] == id && h[1] == ename){
6165 E.un(el, ename, hd);
6166 el = Roo.getDom(el);
6167 if(ename == "mousewheel" && el.addEventListener){
6168 el.removeEventListener("DOMMouseScroll", hd, false);
6170 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6171 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6175 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6182 * @scope Roo.EventManager
6187 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6188 * object with a Roo.EventObject
6189 * @param {Function} fn The method the event invokes
6190 * @param {Object} scope An object that becomes the scope of the handler
6191 * @param {boolean} override If true, the obj passed in becomes
6192 * the execution scope of the listener
6193 * @return {Function} The wrapped function
6196 wrap : function(fn, scope, override){
6198 Roo.EventObject.setEvent(e);
6199 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6204 * Appends an event handler to an element (shorthand for addListener)
6205 * @param {String/HTMLElement} element The html element or id to assign the
6206 * @param {String} eventName The type of event to listen for
6207 * @param {Function} handler The method the event invokes
6208 * @param {Object} scope (optional) The scope in which to execute the handler
6209 * function. The handler function's "this" context.
6210 * @param {Object} options (optional) An object containing handler configuration
6211 * properties. This may contain any of the following properties:<ul>
6212 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6213 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6214 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6215 * <li>preventDefault {Boolean} True to prevent the default action</li>
6216 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6217 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6218 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6219 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6220 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6221 * by the specified number of milliseconds. If the event fires again within that time, the original
6222 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6225 * <b>Combining Options</b><br>
6226 * Using the options argument, it is possible to combine different types of listeners:<br>
6228 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6230 el.on('click', this.onClick, this, {
6237 * <b>Attaching multiple handlers in 1 call</b><br>
6238 * The method also allows for a single argument to be passed which is a config object containing properties
6239 * which specify multiple handlers.
6249 fn: this.onMouseOver
6258 * Or a shorthand syntax:<br>
6261 'click' : this.onClick,
6262 'mouseover' : this.onMouseOver,
6263 'mouseout' : this.onMouseOut
6267 addListener : function(element, eventName, fn, scope, options){
6268 if(typeof eventName == "object"){
6274 if(typeof o[e] == "function"){
6276 listen(element, e, o, o[e], o.scope);
6278 // individual options
6279 listen(element, e, o[e]);
6284 return listen(element, eventName, options, fn, scope);
6288 * Removes an event handler
6290 * @param {String/HTMLElement} element The id or html element to remove the
6292 * @param {String} eventName The type of event
6293 * @param {Function} fn
6294 * @return {Boolean} True if a listener was actually removed
6296 removeListener : function(element, eventName, fn){
6297 return stopListening(element, eventName, fn);
6301 * Fires when the document is ready (before onload and before images are loaded). Can be
6302 * accessed shorthanded Roo.onReady().
6303 * @param {Function} fn The method the event invokes
6304 * @param {Object} scope An object that becomes the scope of the handler
6305 * @param {boolean} options
6307 onDocumentReady : function(fn, scope, options){
6308 if(docReadyState){ // if it already fired
6309 docReadyEvent.addListener(fn, scope, options);
6310 docReadyEvent.fire();
6311 docReadyEvent.clearListeners();
6317 docReadyEvent.addListener(fn, scope, options);
6321 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6322 * @param {Function} fn The method the event invokes
6323 * @param {Object} scope An object that becomes the scope of the handler
6324 * @param {boolean} options
6326 onWindowResize : function(fn, scope, options){
6328 resizeEvent = new Roo.util.Event();
6329 resizeTask = new Roo.util.DelayedTask(function(){
6330 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6332 E.on(window, "resize", function(){
6334 resizeTask.delay(50);
6336 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6340 resizeEvent.addListener(fn, scope, options);
6344 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6345 * @param {Function} fn The method the event invokes
6346 * @param {Object} scope An object that becomes the scope of the handler
6347 * @param {boolean} options
6349 onTextResize : function(fn, scope, options){
6351 textEvent = new Roo.util.Event();
6352 var textEl = new Roo.Element(document.createElement('div'));
6353 textEl.dom.className = 'x-text-resize';
6354 textEl.dom.innerHTML = 'X';
6355 textEl.appendTo(document.body);
6356 textSize = textEl.dom.offsetHeight;
6357 setInterval(function(){
6358 if(textEl.dom.offsetHeight != textSize){
6359 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6361 }, this.textResizeInterval);
6363 textEvent.addListener(fn, scope, options);
6367 * Removes the passed window resize listener.
6368 * @param {Function} fn The method the event invokes
6369 * @param {Object} scope The scope of handler
6371 removeResizeListener : function(fn, scope){
6373 resizeEvent.removeListener(fn, scope);
6378 fireResize : function(){
6380 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6384 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6388 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6390 textResizeInterval : 50
6395 * @scopeAlias pub=Roo.EventManager
6399 * Appends an event handler to an element (shorthand for addListener)
6400 * @param {String/HTMLElement} element The html element or id to assign the
6401 * @param {String} eventName The type of event to listen for
6402 * @param {Function} handler The method the event invokes
6403 * @param {Object} scope (optional) The scope in which to execute the handler
6404 * function. The handler function's "this" context.
6405 * @param {Object} options (optional) An object containing handler configuration
6406 * properties. This may contain any of the following properties:<ul>
6407 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6408 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6409 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6410 * <li>preventDefault {Boolean} True to prevent the default action</li>
6411 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6412 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6413 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6414 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6415 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6416 * by the specified number of milliseconds. If the event fires again within that time, the original
6417 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6420 * <b>Combining Options</b><br>
6421 * Using the options argument, it is possible to combine different types of listeners:<br>
6423 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6425 el.on('click', this.onClick, this, {
6432 * <b>Attaching multiple handlers in 1 call</b><br>
6433 * The method also allows for a single argument to be passed which is a config object containing properties
6434 * which specify multiple handlers.
6444 fn: this.onMouseOver
6453 * Or a shorthand syntax:<br>
6456 'click' : this.onClick,
6457 'mouseover' : this.onMouseOver,
6458 'mouseout' : this.onMouseOut
6462 pub.on = pub.addListener;
6463 pub.un = pub.removeListener;
6465 pub.stoppedMouseDownEvent = new Roo.util.Event();
6469 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6470 * @param {Function} fn The method the event invokes
6471 * @param {Object} scope An object that becomes the scope of the handler
6472 * @param {boolean} override If true, the obj passed in becomes
6473 * the execution scope of the listener
6477 Roo.onReady = Roo.EventManager.onDocumentReady;
6479 Roo.onReady(function(){
6480 var bd = Roo.get(document.body);
6485 : Roo.isGecko ? "roo-gecko"
6486 : Roo.isOpera ? "roo-opera"
6487 : Roo.isSafari ? "roo-safari" : ""];
6490 cls.push("roo-mac");
6493 cls.push("roo-linux");
6495 if(Roo.isBorderBox){
6496 cls.push('roo-border-box');
6498 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6499 var p = bd.dom.parentNode;
6501 p.className += ' roo-strict';
6504 bd.addClass(cls.join(' '));
6508 * @class Roo.EventObject
6509 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6510 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6513 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6515 var target = e.getTarget();
6518 var myDiv = Roo.get("myDiv");
6519 myDiv.on("click", handleClick);
6521 Roo.EventManager.on("myDiv", 'click', handleClick);
6522 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6526 Roo.EventObject = function(){
6528 var E = Roo.lib.Event;
6530 // safari keypress events for special keys return bad keycodes
6533 63235 : 39, // right
6536 63276 : 33, // page up
6537 63277 : 34, // page down
6538 63272 : 46, // delete
6543 // normalize button clicks
6544 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6545 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6547 Roo.EventObjectImpl = function(e){
6549 this.setEvent(e.browserEvent || e);
6552 Roo.EventObjectImpl.prototype = {
6554 * Used to fix doc tools.
6555 * @scope Roo.EventObject.prototype
6561 /** The normal browser event */
6562 browserEvent : null,
6563 /** The button pressed in a mouse event */
6565 /** True if the shift key was down during the event */
6567 /** True if the control key was down during the event */
6569 /** True if the alt key was down during the event */
6628 setEvent : function(e){
6629 if(e == this || (e && e.browserEvent)){ // already wrapped
6632 this.browserEvent = e;
6634 // normalize buttons
6635 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6636 if(e.type == 'click' && this.button == -1){
6640 this.shiftKey = e.shiftKey;
6641 // mac metaKey behaves like ctrlKey
6642 this.ctrlKey = e.ctrlKey || e.metaKey;
6643 this.altKey = e.altKey;
6644 // in getKey these will be normalized for the mac
6645 this.keyCode = e.keyCode;
6646 // keyup warnings on firefox.
6647 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6648 // cache the target for the delayed and or buffered events
6649 this.target = E.getTarget(e);
6651 this.xy = E.getXY(e);
6654 this.shiftKey = false;
6655 this.ctrlKey = false;
6656 this.altKey = false;
6666 * Stop the event (preventDefault and stopPropagation)
6668 stopEvent : function(){
6669 if(this.browserEvent){
6670 if(this.browserEvent.type == 'mousedown'){
6671 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6673 E.stopEvent(this.browserEvent);
6678 * Prevents the browsers default handling of the event.
6680 preventDefault : function(){
6681 if(this.browserEvent){
6682 E.preventDefault(this.browserEvent);
6687 isNavKeyPress : function(){
6688 var k = this.keyCode;
6689 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6690 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6693 isSpecialKey : function(){
6694 var k = this.keyCode;
6695 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6696 (k == 16) || (k == 17) ||
6697 (k >= 18 && k <= 20) ||
6698 (k >= 33 && k <= 35) ||
6699 (k >= 36 && k <= 39) ||
6700 (k >= 44 && k <= 45);
6703 * Cancels bubbling of the event.
6705 stopPropagation : function(){
6706 if(this.browserEvent){
6707 if(this.type == 'mousedown'){
6708 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6710 E.stopPropagation(this.browserEvent);
6715 * Gets the key code for the event.
6718 getCharCode : function(){
6719 return this.charCode || this.keyCode;
6723 * Returns a normalized keyCode for the event.
6724 * @return {Number} The key code
6726 getKey : function(){
6727 var k = this.keyCode || this.charCode;
6728 return Roo.isSafari ? (safariKeys[k] || k) : k;
6732 * Gets the x coordinate of the event.
6735 getPageX : function(){
6740 * Gets the y coordinate of the event.
6743 getPageY : function(){
6748 * Gets the time of the event.
6751 getTime : function(){
6752 if(this.browserEvent){
6753 return E.getTime(this.browserEvent);
6759 * Gets the page coordinates of the event.
6760 * @return {Array} The xy values like [x, y]
6767 * Gets the target for the event.
6768 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6769 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6770 search as a number or element (defaults to 10 || document.body)
6771 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6772 * @return {HTMLelement}
6774 getTarget : function(selector, maxDepth, returnEl){
6775 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6778 * Gets the related target.
6779 * @return {HTMLElement}
6781 getRelatedTarget : function(){
6782 if(this.browserEvent){
6783 return E.getRelatedTarget(this.browserEvent);
6789 * Normalizes mouse wheel delta across browsers
6790 * @return {Number} The delta
6792 getWheelDelta : function(){
6793 var e = this.browserEvent;
6795 if(e.wheelDelta){ /* IE/Opera. */
6796 delta = e.wheelDelta/120;
6797 }else if(e.detail){ /* Mozilla case. */
6798 delta = -e.detail/3;
6804 * Returns true if the control, meta, shift or alt key was pressed during this event.
6807 hasModifier : function(){
6808 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6812 * Returns true if the target of this event equals el or is a child of el
6813 * @param {String/HTMLElement/Element} el
6814 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6817 within : function(el, related){
6818 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6819 return t && Roo.fly(el).contains(t);
6822 getPoint : function(){
6823 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6827 return new Roo.EventObjectImpl();
6832 * Ext JS Library 1.1.1
6833 * Copyright(c) 2006-2007, Ext JS, LLC.
6835 * Originally Released Under LGPL - original licence link has changed is not relivant.
6838 * <script type="text/javascript">
6842 // was in Composite Element!??!?!
6845 var D = Roo.lib.Dom;
6846 var E = Roo.lib.Event;
6847 var A = Roo.lib.Anim;
6849 // local style camelizing for speed
6851 var camelRe = /(-[a-z])/gi;
6852 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6853 var view = document.defaultView;
6856 * @class Roo.Element
6857 * Represents an Element in the DOM.<br><br>
6860 var el = Roo.get("my-div");
6863 var el = getEl("my-div");
6865 // or with a DOM element
6866 var el = Roo.get(myDivElement);
6868 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6869 * each call instead of constructing a new one.<br><br>
6870 * <b>Animations</b><br />
6871 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6872 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6874 Option Default Description
6875 --------- -------- ---------------------------------------------
6876 duration .35 The duration of the animation in seconds
6877 easing easeOut The YUI easing method
6878 callback none A function to execute when the anim completes
6879 scope this The scope (this) of the callback function
6881 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6882 * manipulate the animation. Here's an example:
6884 var el = Roo.get("my-div");
6889 // default animation
6890 el.setWidth(100, true);
6892 // animation with some options set
6899 // using the "anim" property to get the Anim object
6905 el.setWidth(100, opt);
6907 if(opt.anim.isAnimated()){
6911 * <b> Composite (Collections of) Elements</b><br />
6912 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6913 * @constructor Create a new Element directly.
6914 * @param {String/HTMLElement} element
6915 * @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).
6917 Roo.Element = function(element, forceNew){
6918 var dom = typeof element == "string" ?
6919 document.getElementById(element) : element;
6920 if(!dom){ // invalid id/element
6924 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6925 return Roo.Element.cache[id];
6935 * The DOM element ID
6938 this.id = id || Roo.id(dom);
6941 var El = Roo.Element;
6945 * The element's default display mode (defaults to "")
6948 originalDisplay : "",
6952 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6957 * Sets the element's visibility mode. When setVisible() is called it
6958 * will use this to determine whether to set the visibility or the display property.
6959 * @param visMode Element.VISIBILITY or Element.DISPLAY
6960 * @return {Roo.Element} this
6962 setVisibilityMode : function(visMode){
6963 this.visibilityMode = visMode;
6967 * Convenience method for setVisibilityMode(Element.DISPLAY)
6968 * @param {String} display (optional) What to set display to when visible
6969 * @return {Roo.Element} this
6971 enableDisplayMode : function(display){
6972 this.setVisibilityMode(El.DISPLAY);
6973 if(typeof display != "undefined") this.originalDisplay = display;
6978 * 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)
6979 * @param {String} selector The simple selector to test
6980 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6981 search as a number or element (defaults to 10 || document.body)
6982 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6983 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6985 findParent : function(simpleSelector, maxDepth, returnEl){
6986 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6987 maxDepth = maxDepth || 50;
6988 if(typeof maxDepth != "number"){
6989 stopEl = Roo.getDom(maxDepth);
6992 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6993 if(dq.is(p, simpleSelector)){
6994 return returnEl ? Roo.get(p) : p;
7004 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7005 * @param {String} selector The simple selector to test
7006 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7007 search as a number or element (defaults to 10 || document.body)
7008 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7009 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7011 findParentNode : function(simpleSelector, maxDepth, returnEl){
7012 var p = Roo.fly(this.dom.parentNode, '_internal');
7013 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7017 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7018 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7019 * @param {String} selector The simple selector to test
7020 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7021 search as a number or element (defaults to 10 || document.body)
7022 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7024 up : function(simpleSelector, maxDepth){
7025 return this.findParentNode(simpleSelector, maxDepth, true);
7031 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7032 * @param {String} selector The simple selector to test
7033 * @return {Boolean} True if this element matches the selector, else false
7035 is : function(simpleSelector){
7036 return Roo.DomQuery.is(this.dom, simpleSelector);
7040 * Perform animation on this element.
7041 * @param {Object} args The YUI animation control args
7042 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7043 * @param {Function} onComplete (optional) Function to call when animation completes
7044 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7045 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7046 * @return {Roo.Element} this
7048 animate : function(args, duration, onComplete, easing, animType){
7049 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7054 * @private Internal animation call
7056 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7057 animType = animType || 'run';
7059 var anim = Roo.lib.Anim[animType](
7061 (opt.duration || defaultDur) || .35,
7062 (opt.easing || defaultEase) || 'easeOut',
7064 Roo.callback(cb, this);
7065 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7073 // private legacy anim prep
7074 preanim : function(a, i){
7075 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7079 * Removes worthless text nodes
7080 * @param {Boolean} forceReclean (optional) By default the element
7081 * keeps track if it has been cleaned already so
7082 * you can call this over and over. However, if you update the element and
7083 * need to force a reclean, you can pass true.
7085 clean : function(forceReclean){
7086 if(this.isCleaned && forceReclean !== true){
7090 var d = this.dom, n = d.firstChild, ni = -1;
7092 var nx = n.nextSibling;
7093 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7100 this.isCleaned = true;
7105 calcOffsetsTo : function(el){
7108 var restorePos = false;
7109 if(el.getStyle('position') == 'static'){
7110 el.position('relative');
7115 while(op && op != d && op.tagName != 'HTML'){
7118 op = op.offsetParent;
7121 el.position('static');
7127 * Scrolls this element into view within the passed container.
7128 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7129 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7130 * @return {Roo.Element} this
7132 scrollIntoView : function(container, hscroll){
7133 var c = Roo.getDom(container) || document.body;
7136 var o = this.calcOffsetsTo(c),
7139 b = t+el.offsetHeight,
7140 r = l+el.offsetWidth;
7142 var ch = c.clientHeight;
7143 var ct = parseInt(c.scrollTop, 10);
7144 var cl = parseInt(c.scrollLeft, 10);
7146 var cr = cl + c.clientWidth;
7154 if(hscroll !== false){
7158 c.scrollLeft = r-c.clientWidth;
7165 scrollChildIntoView : function(child, hscroll){
7166 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7170 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7171 * the new height may not be available immediately.
7172 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7173 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7174 * @param {Function} onComplete (optional) Function to call when animation completes
7175 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7176 * @return {Roo.Element} this
7178 autoHeight : function(animate, duration, onComplete, easing){
7179 var oldHeight = this.getHeight();
7181 this.setHeight(1); // force clipping
7182 setTimeout(function(){
7183 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7185 this.setHeight(height);
7187 if(typeof onComplete == "function"){
7191 this.setHeight(oldHeight); // restore original height
7192 this.setHeight(height, animate, duration, function(){
7194 if(typeof onComplete == "function") onComplete();
7195 }.createDelegate(this), easing);
7197 }.createDelegate(this), 0);
7202 * Returns true if this element is an ancestor of the passed element
7203 * @param {HTMLElement/String} el The element to check
7204 * @return {Boolean} True if this element is an ancestor of el, else false
7206 contains : function(el){
7207 if(!el){return false;}
7208 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7212 * Checks whether the element is currently visible using both visibility and display properties.
7213 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7214 * @return {Boolean} True if the element is currently visible, else false
7216 isVisible : function(deep) {
7217 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7218 if(deep !== true || !vis){
7221 var p = this.dom.parentNode;
7222 while(p && p.tagName.toLowerCase() != "body"){
7223 if(!Roo.fly(p, '_isVisible').isVisible()){
7232 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7233 * @param {String} selector The CSS selector
7234 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7235 * @return {CompositeElement/CompositeElementLite} The composite element
7237 select : function(selector, unique){
7238 return El.select(selector, unique, this.dom);
7242 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7243 * @param {String} selector The CSS selector
7244 * @return {Array} An array of the matched nodes
7246 query : function(selector, unique){
7247 return Roo.DomQuery.select(selector, this.dom);
7251 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7252 * @param {String} selector The CSS selector
7253 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7254 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7256 child : function(selector, returnDom){
7257 var n = Roo.DomQuery.selectNode(selector, this.dom);
7258 return returnDom ? n : Roo.get(n);
7262 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7263 * @param {String} selector The CSS selector
7264 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7265 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7267 down : function(selector, returnDom){
7268 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7269 return returnDom ? n : Roo.get(n);
7273 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7274 * @param {String} group The group the DD object is member of
7275 * @param {Object} config The DD config object
7276 * @param {Object} overrides An object containing methods to override/implement on the DD object
7277 * @return {Roo.dd.DD} The DD object
7279 initDD : function(group, config, overrides){
7280 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7281 return Roo.apply(dd, overrides);
7285 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7286 * @param {String} group The group the DDProxy object is member of
7287 * @param {Object} config The DDProxy config object
7288 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7289 * @return {Roo.dd.DDProxy} The DDProxy object
7291 initDDProxy : function(group, config, overrides){
7292 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7293 return Roo.apply(dd, overrides);
7297 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7298 * @param {String} group The group the DDTarget object is member of
7299 * @param {Object} config The DDTarget config object
7300 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7301 * @return {Roo.dd.DDTarget} The DDTarget object
7303 initDDTarget : function(group, config, overrides){
7304 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7305 return Roo.apply(dd, overrides);
7309 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7310 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7311 * @param {Boolean} visible Whether the element is visible
7312 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7313 * @return {Roo.Element} this
7315 setVisible : function(visible, animate){
7317 if(this.visibilityMode == El.DISPLAY){
7318 this.setDisplayed(visible);
7321 this.dom.style.visibility = visible ? "visible" : "hidden";
7324 // closure for composites
7326 var visMode = this.visibilityMode;
7328 this.setOpacity(.01);
7329 this.setVisible(true);
7331 this.anim({opacity: { to: (visible?1:0) }},
7332 this.preanim(arguments, 1),
7333 null, .35, 'easeIn', function(){
7335 if(visMode == El.DISPLAY){
7336 dom.style.display = "none";
7338 dom.style.visibility = "hidden";
7340 Roo.get(dom).setOpacity(1);
7348 * Returns true if display is not "none"
7351 isDisplayed : function() {
7352 return this.getStyle("display") != "none";
7356 * Toggles the element's visibility or display, depending on visibility mode.
7357 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7358 * @return {Roo.Element} this
7360 toggle : function(animate){
7361 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7366 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7367 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7368 * @return {Roo.Element} this
7370 setDisplayed : function(value) {
7371 if(typeof value == "boolean"){
7372 value = value ? this.originalDisplay : "none";
7374 this.setStyle("display", value);
7379 * Tries to focus the element. Any exceptions are caught and ignored.
7380 * @return {Roo.Element} this
7382 focus : function() {
7390 * Tries to blur the element. Any exceptions are caught and ignored.
7391 * @return {Roo.Element} this
7401 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7402 * @param {String/Array} className The CSS class to add, or an array of classes
7403 * @return {Roo.Element} this
7405 addClass : function(className){
7406 if(className instanceof Array){
7407 for(var i = 0, len = className.length; i < len; i++) {
7408 this.addClass(className[i]);
7411 if(className && !this.hasClass(className)){
7412 this.dom.className = this.dom.className + " " + className;
7419 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7420 * @param {String/Array} className The CSS class to add, or an array of classes
7421 * @return {Roo.Element} this
7423 radioClass : function(className){
7424 var siblings = this.dom.parentNode.childNodes;
7425 for(var i = 0; i < siblings.length; i++) {
7426 var s = siblings[i];
7427 if(s.nodeType == 1){
7428 Roo.get(s).removeClass(className);
7431 this.addClass(className);
7436 * Removes one or more CSS classes from the element.
7437 * @param {String/Array} className The CSS class to remove, or an array of classes
7438 * @return {Roo.Element} this
7440 removeClass : function(className){
7441 if(!className || !this.dom.className){
7444 if(className instanceof Array){
7445 for(var i = 0, len = className.length; i < len; i++) {
7446 this.removeClass(className[i]);
7449 if(this.hasClass(className)){
7450 var re = this.classReCache[className];
7452 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7453 this.classReCache[className] = re;
7455 this.dom.className =
7456 this.dom.className.replace(re, " ");
7466 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7467 * @param {String} className The CSS class to toggle
7468 * @return {Roo.Element} this
7470 toggleClass : function(className){
7471 if(this.hasClass(className)){
7472 this.removeClass(className);
7474 this.addClass(className);
7480 * Checks if the specified CSS class exists on this element's DOM node.
7481 * @param {String} className The CSS class to check for
7482 * @return {Boolean} True if the class exists, else false
7484 hasClass : function(className){
7485 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7489 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7490 * @param {String} oldClassName The CSS class to replace
7491 * @param {String} newClassName The replacement CSS class
7492 * @return {Roo.Element} this
7494 replaceClass : function(oldClassName, newClassName){
7495 this.removeClass(oldClassName);
7496 this.addClass(newClassName);
7501 * Returns an object with properties matching the styles requested.
7502 * For example, el.getStyles('color', 'font-size', 'width') might return
7503 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7504 * @param {String} style1 A style name
7505 * @param {String} style2 A style name
7506 * @param {String} etc.
7507 * @return {Object} The style object
7509 getStyles : function(){
7510 var a = arguments, len = a.length, r = {};
7511 for(var i = 0; i < len; i++){
7512 r[a[i]] = this.getStyle(a[i]);
7518 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7519 * @param {String} property The style property whose value is returned.
7520 * @return {String} The current value of the style property for this element.
7522 getStyle : function(){
7523 return view && view.getComputedStyle ?
7525 var el = this.dom, v, cs, camel;
7526 if(prop == 'float'){
7529 if(el.style && (v = el.style[prop])){
7532 if(cs = view.getComputedStyle(el, "")){
7533 if(!(camel = propCache[prop])){
7534 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7541 var el = this.dom, v, cs, camel;
7542 if(prop == 'opacity'){
7543 if(typeof el.style.filter == 'string'){
7544 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7546 var fv = parseFloat(m[1]);
7548 return fv ? fv / 100 : 0;
7553 }else if(prop == 'float'){
7554 prop = "styleFloat";
7556 if(!(camel = propCache[prop])){
7557 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7559 if(v = el.style[camel]){
7562 if(cs = el.currentStyle){
7570 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7571 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7572 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7573 * @return {Roo.Element} this
7575 setStyle : function(prop, value){
7576 if(typeof prop == "string"){
7578 if (prop == 'float') {
7579 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7588 if(camel == 'opacity') {
7589 this.setOpacity(value);
7591 this.dom.style[camel] = value;
7594 for(var style in prop){
7595 if(typeof prop[style] != "function"){
7596 this.setStyle(style, prop[style]);
7604 * More flexible version of {@link #setStyle} for setting style properties.
7605 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7606 * a function which returns such a specification.
7607 * @return {Roo.Element} this
7609 applyStyles : function(style){
7610 Roo.DomHelper.applyStyles(this.dom, style);
7615 * 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).
7616 * @return {Number} The X position of the element
7619 return D.getX(this.dom);
7623 * 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).
7624 * @return {Number} The Y position of the element
7627 return D.getY(this.dom);
7631 * 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).
7632 * @return {Array} The XY position of the element
7635 return D.getXY(this.dom);
7639 * 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).
7640 * @param {Number} The X position of the element
7641 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7642 * @return {Roo.Element} this
7644 setX : function(x, animate){
7646 D.setX(this.dom, x);
7648 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7654 * 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).
7655 * @param {Number} The Y position of the element
7656 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7657 * @return {Roo.Element} this
7659 setY : function(y, animate){
7661 D.setY(this.dom, y);
7663 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7669 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7670 * @param {String} left The left CSS property value
7671 * @return {Roo.Element} this
7673 setLeft : function(left){
7674 this.setStyle("left", this.addUnits(left));
7679 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7680 * @param {String} top The top CSS property value
7681 * @return {Roo.Element} this
7683 setTop : function(top){
7684 this.setStyle("top", this.addUnits(top));
7689 * Sets the element's CSS right style.
7690 * @param {String} right The right CSS property value
7691 * @return {Roo.Element} this
7693 setRight : function(right){
7694 this.setStyle("right", this.addUnits(right));
7699 * Sets the element's CSS bottom style.
7700 * @param {String} bottom The bottom CSS property value
7701 * @return {Roo.Element} this
7703 setBottom : function(bottom){
7704 this.setStyle("bottom", this.addUnits(bottom));
7709 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7710 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7711 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7712 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7713 * @return {Roo.Element} this
7715 setXY : function(pos, animate){
7717 D.setXY(this.dom, pos);
7719 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7725 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7726 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7727 * @param {Number} x X value for new position (coordinates are page-based)
7728 * @param {Number} y Y value for new position (coordinates are page-based)
7729 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7730 * @return {Roo.Element} this
7732 setLocation : function(x, y, animate){
7733 this.setXY([x, y], this.preanim(arguments, 2));
7738 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7739 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7740 * @param {Number} x X value for new position (coordinates are page-based)
7741 * @param {Number} y Y value for new position (coordinates are page-based)
7742 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7743 * @return {Roo.Element} this
7745 moveTo : function(x, y, animate){
7746 this.setXY([x, y], this.preanim(arguments, 2));
7751 * Returns the region of the given element.
7752 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7753 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7755 getRegion : function(){
7756 return D.getRegion(this.dom);
7760 * Returns the offset height of the element
7761 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7762 * @return {Number} The element's height
7764 getHeight : function(contentHeight){
7765 var h = this.dom.offsetHeight || 0;
7766 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7770 * Returns the offset width of the element
7771 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7772 * @return {Number} The element's width
7774 getWidth : function(contentWidth){
7775 var w = this.dom.offsetWidth || 0;
7776 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7780 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7781 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7782 * if a height has not been set using CSS.
7785 getComputedHeight : function(){
7786 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7788 h = parseInt(this.getStyle('height'), 10) || 0;
7789 if(!this.isBorderBox()){
7790 h += this.getFrameWidth('tb');
7797 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7798 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7799 * if a width has not been set using CSS.
7802 getComputedWidth : function(){
7803 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7805 w = parseInt(this.getStyle('width'), 10) || 0;
7806 if(!this.isBorderBox()){
7807 w += this.getFrameWidth('lr');
7814 * Returns the size of the element.
7815 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7816 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7818 getSize : function(contentSize){
7819 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7823 * Returns the width and height of the viewport.
7824 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7826 getViewSize : function(){
7827 var d = this.dom, doc = document, aw = 0, ah = 0;
7828 if(d == doc || d == doc.body){
7829 return {width : D.getViewWidth(), height: D.getViewHeight()};
7832 width : d.clientWidth,
7833 height: d.clientHeight
7839 * Returns the value of the "value" attribute
7840 * @param {Boolean} asNumber true to parse the value as a number
7841 * @return {String/Number}
7843 getValue : function(asNumber){
7844 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7848 adjustWidth : function(width){
7849 if(typeof width == "number"){
7850 if(this.autoBoxAdjust && !this.isBorderBox()){
7851 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7861 adjustHeight : function(height){
7862 if(typeof height == "number"){
7863 if(this.autoBoxAdjust && !this.isBorderBox()){
7864 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7874 * Set the width of the element
7875 * @param {Number} width The new width
7876 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7877 * @return {Roo.Element} this
7879 setWidth : function(width, animate){
7880 width = this.adjustWidth(width);
7882 this.dom.style.width = this.addUnits(width);
7884 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7890 * Set the height of the element
7891 * @param {Number} height The new height
7892 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7893 * @return {Roo.Element} this
7895 setHeight : function(height, animate){
7896 height = this.adjustHeight(height);
7898 this.dom.style.height = this.addUnits(height);
7900 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7906 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7907 * @param {Number} width The new width
7908 * @param {Number} height The new height
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setSize : function(width, height, animate){
7913 if(typeof width == "object"){ // in case of object from getSize()
7914 height = width.height; width = width.width;
7916 width = this.adjustWidth(width); height = this.adjustHeight(height);
7918 this.dom.style.width = this.addUnits(width);
7919 this.dom.style.height = this.addUnits(height);
7921 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7927 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7928 * @param {Number} x X value for new position (coordinates are page-based)
7929 * @param {Number} y Y value for new position (coordinates are page-based)
7930 * @param {Number} width The new width
7931 * @param {Number} height The new height
7932 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7933 * @return {Roo.Element} this
7935 setBounds : function(x, y, width, height, animate){
7937 this.setSize(width, height);
7938 this.setLocation(x, y);
7940 width = this.adjustWidth(width); height = this.adjustHeight(height);
7941 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7942 this.preanim(arguments, 4), 'motion');
7948 * 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.
7949 * @param {Roo.lib.Region} region The region to fill
7950 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7951 * @return {Roo.Element} this
7953 setRegion : function(region, animate){
7954 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7959 * Appends an event handler
7961 * @param {String} eventName The type of event to append
7962 * @param {Function} fn The method the event invokes
7963 * @param {Object} scope (optional) The scope (this object) of the fn
7964 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7966 addListener : function(eventName, fn, scope, options){
7968 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7973 * Removes an event handler from this element
7974 * @param {String} eventName the type of event to remove
7975 * @param {Function} fn the method the event invokes
7976 * @return {Roo.Element} this
7978 removeListener : function(eventName, fn){
7979 Roo.EventManager.removeListener(this.dom, eventName, fn);
7984 * Removes all previous added listeners from this element
7985 * @return {Roo.Element} this
7987 removeAllListeners : function(){
7988 E.purgeElement(this.dom);
7992 relayEvent : function(eventName, observable){
7993 this.on(eventName, function(e){
7994 observable.fireEvent(eventName, e);
7999 * Set the opacity of the element
8000 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8001 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8002 * @return {Roo.Element} this
8004 setOpacity : function(opacity, animate){
8006 var s = this.dom.style;
8009 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8010 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8012 s.opacity = opacity;
8015 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8021 * Gets the left X coordinate
8022 * @param {Boolean} local True to get the local css position instead of page coordinate
8025 getLeft : function(local){
8029 return parseInt(this.getStyle("left"), 10) || 0;
8034 * Gets the right X coordinate of the element (element X position + element width)
8035 * @param {Boolean} local True to get the local css position instead of page coordinate
8038 getRight : function(local){
8040 return this.getX() + this.getWidth();
8042 return (this.getLeft(true) + this.getWidth()) || 0;
8047 * Gets the top Y coordinate
8048 * @param {Boolean} local True to get the local css position instead of page coordinate
8051 getTop : function(local) {
8055 return parseInt(this.getStyle("top"), 10) || 0;
8060 * Gets the bottom Y coordinate of the element (element Y position + element height)
8061 * @param {Boolean} local True to get the local css position instead of page coordinate
8064 getBottom : function(local){
8066 return this.getY() + this.getHeight();
8068 return (this.getTop(true) + this.getHeight()) || 0;
8073 * Initializes positioning on this element. If a desired position is not passed, it will make the
8074 * the element positioned relative IF it is not already positioned.
8075 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8076 * @param {Number} zIndex (optional) The zIndex to apply
8077 * @param {Number} x (optional) Set the page X position
8078 * @param {Number} y (optional) Set the page Y position
8080 position : function(pos, zIndex, x, y){
8082 if(this.getStyle('position') == 'static'){
8083 this.setStyle('position', 'relative');
8086 this.setStyle("position", pos);
8089 this.setStyle("z-index", zIndex);
8091 if(x !== undefined && y !== undefined){
8093 }else if(x !== undefined){
8095 }else if(y !== undefined){
8101 * Clear positioning back to the default when the document was loaded
8102 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8103 * @return {Roo.Element} this
8105 clearPositioning : function(value){
8113 "position" : "static"
8119 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8120 * snapshot before performing an update and then restoring the element.
8123 getPositioning : function(){
8124 var l = this.getStyle("left");
8125 var t = this.getStyle("top");
8127 "position" : this.getStyle("position"),
8129 "right" : l ? "" : this.getStyle("right"),
8131 "bottom" : t ? "" : this.getStyle("bottom"),
8132 "z-index" : this.getStyle("z-index")
8137 * Gets the width of the border(s) for the specified side(s)
8138 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8139 * passing lr would get the border (l)eft width + the border (r)ight width.
8140 * @return {Number} The width of the sides passed added together
8142 getBorderWidth : function(side){
8143 return this.addStyles(side, El.borders);
8147 * Gets the width of the padding(s) for the specified side(s)
8148 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8149 * passing lr would get the padding (l)eft + the padding (r)ight.
8150 * @return {Number} The padding of the sides passed added together
8152 getPadding : function(side){
8153 return this.addStyles(side, El.paddings);
8157 * Set positioning with an object returned by getPositioning().
8158 * @param {Object} posCfg
8159 * @return {Roo.Element} this
8161 setPositioning : function(pc){
8162 this.applyStyles(pc);
8163 if(pc.right == "auto"){
8164 this.dom.style.right = "";
8166 if(pc.bottom == "auto"){
8167 this.dom.style.bottom = "";
8173 fixDisplay : function(){
8174 if(this.getStyle("display") == "none"){
8175 this.setStyle("visibility", "hidden");
8176 this.setStyle("display", this.originalDisplay); // first try reverting to default
8177 if(this.getStyle("display") == "none"){ // if that fails, default to block
8178 this.setStyle("display", "block");
8184 * Quick set left and top adding default units
8185 * @param {String} left The left CSS property value
8186 * @param {String} top The top CSS property value
8187 * @return {Roo.Element} this
8189 setLeftTop : function(left, top){
8190 this.dom.style.left = this.addUnits(left);
8191 this.dom.style.top = this.addUnits(top);
8196 * Move this element relative to its current position.
8197 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8198 * @param {Number} distance How far to move the element in pixels
8199 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8200 * @return {Roo.Element} this
8202 move : function(direction, distance, animate){
8203 var xy = this.getXY();
8204 direction = direction.toLowerCase();
8208 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8212 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8217 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8222 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8229 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8230 * @return {Roo.Element} this
8233 if(!this.isClipped){
8234 this.isClipped = true;
8235 this.originalClip = {
8236 "o": this.getStyle("overflow"),
8237 "x": this.getStyle("overflow-x"),
8238 "y": this.getStyle("overflow-y")
8240 this.setStyle("overflow", "hidden");
8241 this.setStyle("overflow-x", "hidden");
8242 this.setStyle("overflow-y", "hidden");
8248 * Return clipping (overflow) to original clipping before clip() was called
8249 * @return {Roo.Element} this
8251 unclip : function(){
8253 this.isClipped = false;
8254 var o = this.originalClip;
8255 if(o.o){this.setStyle("overflow", o.o);}
8256 if(o.x){this.setStyle("overflow-x", o.x);}
8257 if(o.y){this.setStyle("overflow-y", o.y);}
8264 * Gets the x,y coordinates specified by the anchor position on the element.
8265 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8266 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8267 * {width: (target width), height: (target height)} (defaults to the element's current size)
8268 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8269 * @return {Array} [x, y] An array containing the element's x and y coordinates
8271 getAnchorXY : function(anchor, local, s){
8272 //Passing a different size is useful for pre-calculating anchors,
8273 //especially for anchored animations that change the el size.
8275 var w, h, vp = false;
8278 if(d == document.body || d == document){
8280 w = D.getViewWidth(); h = D.getViewHeight();
8282 w = this.getWidth(); h = this.getHeight();
8285 w = s.width; h = s.height;
8287 var x = 0, y = 0, r = Math.round;
8288 switch((anchor || "tl").toLowerCase()){
8330 var sc = this.getScroll();
8331 return [x + sc.left, y + sc.top];
8333 //Add the element's offset xy
8334 var o = this.getXY();
8335 return [x+o[0], y+o[1]];
8339 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8340 * supported position values.
8341 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8342 * @param {String} position The position to align to.
8343 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8344 * @return {Array} [x, y]
8346 getAlignToXY : function(el, p, o){
8350 throw "Element.alignTo with an element that doesn't exist";
8352 var c = false; //constrain to viewport
8353 var p1 = "", p2 = "";
8360 }else if(p.indexOf("-") == -1){
8363 p = p.toLowerCase();
8364 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8366 throw "Element.alignTo with an invalid alignment " + p;
8368 p1 = m[1]; p2 = m[2]; c = !!m[3];
8370 //Subtract the aligned el's internal xy from the target's offset xy
8371 //plus custom offset to get the aligned el's new offset xy
8372 var a1 = this.getAnchorXY(p1, true);
8373 var a2 = el.getAnchorXY(p2, false);
8374 var x = a2[0] - a1[0] + o[0];
8375 var y = a2[1] - a1[1] + o[1];
8377 //constrain the aligned el to viewport if necessary
8378 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8379 // 5px of margin for ie
8380 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8382 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8383 //perpendicular to the vp border, allow the aligned el to slide on that border,
8384 //otherwise swap the aligned el to the opposite border of the target.
8385 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8386 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8387 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8388 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8391 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8392 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8394 if((x+w) > dw + scrollX){
8395 x = swapX ? r.left-w : dw+scrollX-w;
8398 x = swapX ? r.right : scrollX;
8400 if((y+h) > dh + scrollY){
8401 y = swapY ? r.top-h : dh+scrollY-h;
8404 y = swapY ? r.bottom : scrollY;
8411 getConstrainToXY : function(){
8412 var os = {top:0, left:0, bottom:0, right: 0};
8414 return function(el, local, offsets, proposedXY){
8416 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8418 var vw, vh, vx = 0, vy = 0;
8419 if(el.dom == document.body || el.dom == document){
8420 vw = Roo.lib.Dom.getViewWidth();
8421 vh = Roo.lib.Dom.getViewHeight();
8423 vw = el.dom.clientWidth;
8424 vh = el.dom.clientHeight;
8426 var vxy = el.getXY();
8432 var s = el.getScroll();
8434 vx += offsets.left + s.left;
8435 vy += offsets.top + s.top;
8437 vw -= offsets.right;
8438 vh -= offsets.bottom;
8443 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8444 var x = xy[0], y = xy[1];
8445 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8447 // only move it if it needs it
8450 // first validate right/bottom
8459 // then make sure top/left isn't negative
8468 return moved ? [x, y] : false;
8473 adjustForConstraints : function(xy, parent, offsets){
8474 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8478 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8479 * document it aligns it to the viewport.
8480 * The position parameter is optional, and can be specified in any one of the following formats:
8482 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8483 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8484 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8485 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8486 * <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
8487 * element's anchor point, and the second value is used as the target's anchor point.</li>
8489 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8490 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8491 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8492 * that specified in order to enforce the viewport constraints.
8493 * Following are all of the supported anchor positions:
8496 ----- -----------------------------
8497 tl The top left corner (default)
8498 t The center of the top edge
8499 tr The top right corner
8500 l The center of the left edge
8501 c In the center of the element
8502 r The center of the right edge
8503 bl The bottom left corner
8504 b The center of the bottom edge
8505 br The bottom right corner
8509 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8510 el.alignTo("other-el");
8512 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8513 el.alignTo("other-el", "tr?");
8515 // align the bottom right corner of el with the center left edge of other-el
8516 el.alignTo("other-el", "br-l?");
8518 // align the center of el with the bottom left corner of other-el and
8519 // adjust the x position by -6 pixels (and the y position by 0)
8520 el.alignTo("other-el", "c-bl", [-6, 0]);
8522 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8523 * @param {String} position The position to align to.
8524 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8525 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8526 * @return {Roo.Element} this
8528 alignTo : function(element, position, offsets, animate){
8529 var xy = this.getAlignToXY(element, position, offsets);
8530 this.setXY(xy, this.preanim(arguments, 3));
8535 * Anchors an element to another element and realigns it when the window is resized.
8536 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8537 * @param {String} position The position to align to.
8538 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8539 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8540 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8541 * is a number, it is used as the buffer delay (defaults to 50ms).
8542 * @param {Function} callback The function to call after the animation finishes
8543 * @return {Roo.Element} this
8545 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8546 var action = function(){
8547 this.alignTo(el, alignment, offsets, animate);
8548 Roo.callback(callback, this);
8550 Roo.EventManager.onWindowResize(action, this);
8551 var tm = typeof monitorScroll;
8552 if(tm != 'undefined'){
8553 Roo.EventManager.on(window, 'scroll', action, this,
8554 {buffer: tm == 'number' ? monitorScroll : 50});
8556 action.call(this); // align immediately
8560 * Clears any opacity settings from this element. Required in some cases for IE.
8561 * @return {Roo.Element} this
8563 clearOpacity : function(){
8564 if (window.ActiveXObject) {
8565 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8566 this.dom.style.filter = "";
8569 this.dom.style.opacity = "";
8570 this.dom.style["-moz-opacity"] = "";
8571 this.dom.style["-khtml-opacity"] = "";
8577 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8578 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8579 * @return {Roo.Element} this
8581 hide : function(animate){
8582 this.setVisible(false, this.preanim(arguments, 0));
8587 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8588 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8589 * @return {Roo.Element} this
8591 show : function(animate){
8592 this.setVisible(true, this.preanim(arguments, 0));
8597 * @private Test if size has a unit, otherwise appends the default
8599 addUnits : function(size){
8600 return Roo.Element.addUnits(size, this.defaultUnit);
8604 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8605 * @return {Roo.Element} this
8607 beginMeasure : function(){
8609 if(el.offsetWidth || el.offsetHeight){
8610 return this; // offsets work already
8613 var p = this.dom, b = document.body; // start with this element
8614 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8615 var pe = Roo.get(p);
8616 if(pe.getStyle('display') == 'none'){
8617 changed.push({el: p, visibility: pe.getStyle("visibility")});
8618 p.style.visibility = "hidden";
8619 p.style.display = "block";
8623 this._measureChanged = changed;
8629 * Restores displays to before beginMeasure was called
8630 * @return {Roo.Element} this
8632 endMeasure : function(){
8633 var changed = this._measureChanged;
8635 for(var i = 0, len = changed.length; i < len; i++) {
8637 r.el.style.visibility = r.visibility;
8638 r.el.style.display = "none";
8640 this._measureChanged = null;
8646 * Update the innerHTML of this element, optionally searching for and processing scripts
8647 * @param {String} html The new HTML
8648 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8649 * @param {Function} callback For async script loading you can be noticed when the update completes
8650 * @return {Roo.Element} this
8652 update : function(html, loadScripts, callback){
8653 if(typeof html == "undefined"){
8656 if(loadScripts !== true){
8657 this.dom.innerHTML = html;
8658 if(typeof callback == "function"){
8666 html += '<span id="' + id + '"></span>';
8668 E.onAvailable(id, function(){
8669 var hd = document.getElementsByTagName("head")[0];
8670 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8671 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8672 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8675 while(match = re.exec(html)){
8676 var attrs = match[1];
8677 var srcMatch = attrs ? attrs.match(srcRe) : false;
8678 if(srcMatch && srcMatch[2]){
8679 var s = document.createElement("script");
8680 s.src = srcMatch[2];
8681 var typeMatch = attrs.match(typeRe);
8682 if(typeMatch && typeMatch[2]){
8683 s.type = typeMatch[2];
8686 }else if(match[2] && match[2].length > 0){
8687 if(window.execScript) {
8688 window.execScript(match[2]);
8696 window.eval(match[2]);
8700 var el = document.getElementById(id);
8701 if(el){el.parentNode.removeChild(el);}
8702 if(typeof callback == "function"){
8706 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8711 * Direct access to the UpdateManager update() method (takes the same parameters).
8712 * @param {String/Function} url The url for this request or a function to call to get the url
8713 * @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}
8714 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8715 * @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.
8716 * @return {Roo.Element} this
8719 var um = this.getUpdateManager();
8720 um.update.apply(um, arguments);
8725 * Gets this element's UpdateManager
8726 * @return {Roo.UpdateManager} The UpdateManager
8728 getUpdateManager : function(){
8729 if(!this.updateManager){
8730 this.updateManager = new Roo.UpdateManager(this);
8732 return this.updateManager;
8736 * Disables text selection for this element (normalized across browsers)
8737 * @return {Roo.Element} this
8739 unselectable : function(){
8740 this.dom.unselectable = "on";
8741 this.swallowEvent("selectstart", true);
8742 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8743 this.addClass("x-unselectable");
8748 * Calculates the x, y to center this element on the screen
8749 * @return {Array} The x, y values [x, y]
8751 getCenterXY : function(){
8752 return this.getAlignToXY(document, 'c-c');
8756 * Centers the Element in either the viewport, or another Element.
8757 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8759 center : function(centerIn){
8760 this.alignTo(centerIn || document, 'c-c');
8765 * Tests various css rules/browsers to determine if this element uses a border box
8768 isBorderBox : function(){
8769 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8773 * Return a box {x, y, width, height} that can be used to set another elements
8774 * size/location to match this element.
8775 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8776 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8777 * @return {Object} box An object in the format {x, y, width, height}
8779 getBox : function(contentBox, local){
8784 var left = parseInt(this.getStyle("left"), 10) || 0;
8785 var top = parseInt(this.getStyle("top"), 10) || 0;
8788 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8790 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8792 var l = this.getBorderWidth("l")+this.getPadding("l");
8793 var r = this.getBorderWidth("r")+this.getPadding("r");
8794 var t = this.getBorderWidth("t")+this.getPadding("t");
8795 var b = this.getBorderWidth("b")+this.getPadding("b");
8796 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)};
8798 bx.right = bx.x + bx.width;
8799 bx.bottom = bx.y + bx.height;
8804 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8805 for more information about the sides.
8806 * @param {String} sides
8809 getFrameWidth : function(sides, onlyContentBox){
8810 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8814 * 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.
8815 * @param {Object} box The box to fill {x, y, width, height}
8816 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8817 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8818 * @return {Roo.Element} this
8820 setBox : function(box, adjust, animate){
8821 var w = box.width, h = box.height;
8822 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8823 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8824 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8826 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8831 * Forces the browser to repaint this element
8832 * @return {Roo.Element} this
8834 repaint : function(){
8836 this.addClass("x-repaint");
8837 setTimeout(function(){
8838 Roo.get(dom).removeClass("x-repaint");
8844 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8845 * then it returns the calculated width of the sides (see getPadding)
8846 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8847 * @return {Object/Number}
8849 getMargins : function(side){
8852 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8853 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8854 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8855 right: parseInt(this.getStyle("margin-right"), 10) || 0
8858 return this.addStyles(side, El.margins);
8863 addStyles : function(sides, styles){
8865 for(var i = 0, len = sides.length; i < len; i++){
8866 v = this.getStyle(styles[sides.charAt(i)]);
8868 w = parseInt(v, 10);
8876 * Creates a proxy element of this element
8877 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8878 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8879 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8880 * @return {Roo.Element} The new proxy element
8882 createProxy : function(config, renderTo, matchBox){
8884 renderTo = Roo.getDom(renderTo);
8886 renderTo = document.body;
8888 config = typeof config == "object" ?
8889 config : {tag : "div", cls: config};
8890 var proxy = Roo.DomHelper.append(renderTo, config, true);
8892 proxy.setBox(this.getBox());
8898 * Puts a mask over this element to disable user interaction. Requires core.css.
8899 * This method can only be applied to elements which accept child nodes.
8900 * @param {String} msg (optional) A message to display in the mask
8901 * @param {String} msgCls (optional) A css class to apply to the msg element
8902 * @return {Element} The mask element
8904 mask : function(msg, msgCls)
8906 if(this.getStyle("position") == "static"){
8907 this.setStyle("position", "relative");
8910 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8912 this.addClass("x-masked");
8913 this._mask.setDisplayed(true);
8918 while (dom && dom.style) {
8919 if (!isNaN(parseInt(dom.style.zIndex))) {
8920 z = Math.max(z, parseInt(dom.style.zIndex));
8922 dom = dom.parentNode;
8924 // if we are masking the body - then it hides everything..
8925 if (this.dom == document.body) {
8927 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8928 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8931 if(typeof msg == 'string'){
8933 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8935 var mm = this._maskMsg;
8936 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8937 mm.dom.firstChild.innerHTML = msg;
8938 mm.setDisplayed(true);
8940 mm.setStyle('z-index', z + 102);
8942 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8943 this._mask.setHeight(this.getHeight());
8945 this._mask.setStyle('z-index', z + 100);
8951 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8952 * it is cached for reuse.
8954 unmask : function(removeEl){
8956 if(removeEl === true){
8957 this._mask.remove();
8960 this._maskMsg.remove();
8961 delete this._maskMsg;
8964 this._mask.setDisplayed(false);
8966 this._maskMsg.setDisplayed(false);
8970 this.removeClass("x-masked");
8974 * Returns true if this element is masked
8977 isMasked : function(){
8978 return this._mask && this._mask.isVisible();
8982 * Creates an iframe shim for this element to keep selects and other windowed objects from
8984 * @return {Roo.Element} The new shim element
8986 createShim : function(){
8987 var el = document.createElement('iframe');
8988 el.frameBorder = 'no';
8989 el.className = 'roo-shim';
8990 if(Roo.isIE && Roo.isSecure){
8991 el.src = Roo.SSL_SECURE_URL;
8993 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8994 shim.autoBoxAdjust = false;
8999 * Removes this element from the DOM and deletes it from the cache
9001 remove : function(){
9002 if(this.dom.parentNode){
9003 this.dom.parentNode.removeChild(this.dom);
9005 delete El.cache[this.dom.id];
9009 * Sets up event handlers to add and remove a css class when the mouse is over this element
9010 * @param {String} className
9011 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9012 * mouseout events for children elements
9013 * @return {Roo.Element} this
9015 addClassOnOver : function(className, preventFlicker){
9016 this.on("mouseover", function(){
9017 Roo.fly(this, '_internal').addClass(className);
9019 var removeFn = function(e){
9020 if(preventFlicker !== true || !e.within(this, true)){
9021 Roo.fly(this, '_internal').removeClass(className);
9024 this.on("mouseout", removeFn, this.dom);
9029 * Sets up event handlers to add and remove a css class when this element has the focus
9030 * @param {String} className
9031 * @return {Roo.Element} this
9033 addClassOnFocus : function(className){
9034 this.on("focus", function(){
9035 Roo.fly(this, '_internal').addClass(className);
9037 this.on("blur", function(){
9038 Roo.fly(this, '_internal').removeClass(className);
9043 * 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)
9044 * @param {String} className
9045 * @return {Roo.Element} this
9047 addClassOnClick : function(className){
9049 this.on("mousedown", function(){
9050 Roo.fly(dom, '_internal').addClass(className);
9051 var d = Roo.get(document);
9052 var fn = function(){
9053 Roo.fly(dom, '_internal').removeClass(className);
9054 d.removeListener("mouseup", fn);
9056 d.on("mouseup", fn);
9062 * Stops the specified event from bubbling and optionally prevents the default action
9063 * @param {String} eventName
9064 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9065 * @return {Roo.Element} this
9067 swallowEvent : function(eventName, preventDefault){
9068 var fn = function(e){
9069 e.stopPropagation();
9074 if(eventName instanceof Array){
9075 for(var i = 0, len = eventName.length; i < len; i++){
9076 this.on(eventName[i], fn);
9080 this.on(eventName, fn);
9087 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9090 * Sizes this element to its parent element's dimensions performing
9091 * neccessary box adjustments.
9092 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9093 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9094 * @return {Roo.Element} this
9096 fitToParent : function(monitorResize, targetParent) {
9097 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9098 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9099 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9102 var p = Roo.get(targetParent || this.dom.parentNode);
9103 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9104 if (monitorResize === true) {
9105 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9106 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9112 * Gets the next sibling, skipping text nodes
9113 * @return {HTMLElement} The next sibling or null
9115 getNextSibling : function(){
9116 var n = this.dom.nextSibling;
9117 while(n && n.nodeType != 1){
9124 * Gets the previous sibling, skipping text nodes
9125 * @return {HTMLElement} The previous sibling or null
9127 getPrevSibling : function(){
9128 var n = this.dom.previousSibling;
9129 while(n && n.nodeType != 1){
9130 n = n.previousSibling;
9137 * Appends the passed element(s) to this element
9138 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9139 * @return {Roo.Element} this
9141 appendChild: function(el){
9148 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9149 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9150 * automatically generated with the specified attributes.
9151 * @param {HTMLElement} insertBefore (optional) a child element of this element
9152 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9153 * @return {Roo.Element} The new child element
9155 createChild: function(config, insertBefore, returnDom){
9156 config = config || {tag:'div'};
9158 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9160 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9164 * Appends this element to the passed element
9165 * @param {String/HTMLElement/Element} el The new parent element
9166 * @return {Roo.Element} this
9168 appendTo: function(el){
9169 el = Roo.getDom(el);
9170 el.appendChild(this.dom);
9175 * Inserts this element before the passed element in the DOM
9176 * @param {String/HTMLElement/Element} el The element to insert before
9177 * @return {Roo.Element} this
9179 insertBefore: function(el){
9180 el = Roo.getDom(el);
9181 el.parentNode.insertBefore(this.dom, el);
9186 * Inserts this element after the passed element in the DOM
9187 * @param {String/HTMLElement/Element} el The element to insert after
9188 * @return {Roo.Element} this
9190 insertAfter: function(el){
9191 el = Roo.getDom(el);
9192 el.parentNode.insertBefore(this.dom, el.nextSibling);
9197 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9198 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9199 * @return {Roo.Element} The new child
9201 insertFirst: function(el, returnDom){
9203 if(typeof el == 'object' && !el.nodeType){ // dh config
9204 return this.createChild(el, this.dom.firstChild, returnDom);
9206 el = Roo.getDom(el);
9207 this.dom.insertBefore(el, this.dom.firstChild);
9208 return !returnDom ? Roo.get(el) : el;
9213 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9214 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9215 * @param {String} where (optional) 'before' or 'after' defaults to before
9216 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9217 * @return {Roo.Element} the inserted Element
9219 insertSibling: function(el, where, returnDom){
9220 where = where ? where.toLowerCase() : 'before';
9222 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9224 if(typeof el == 'object' && !el.nodeType){ // dh config
9225 if(where == 'after' && !this.dom.nextSibling){
9226 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9228 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9232 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9233 where == 'before' ? this.dom : this.dom.nextSibling);
9242 * Creates and wraps this element with another element
9243 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {HTMLElement/Element} The newly created wrapper element
9247 wrap: function(config, returnDom){
9249 config = {tag: "div"};
9251 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9252 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9257 * Replaces the passed element with this element
9258 * @param {String/HTMLElement/Element} el The element to replace
9259 * @return {Roo.Element} this
9261 replace: function(el){
9263 this.insertBefore(el);
9269 * Inserts an html fragment into this element
9270 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9271 * @param {String} html The HTML fragment
9272 * @param {Boolean} returnEl True to return an Roo.Element
9273 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9275 insertHtml : function(where, html, returnEl){
9276 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9277 return returnEl ? Roo.get(el) : el;
9281 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9282 * @param {Object} o The object with the attributes
9283 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9284 * @return {Roo.Element} this
9286 set : function(o, useSet){
9288 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9290 if(attr == "style" || typeof o[attr] == "function") continue;
9292 el.className = o["cls"];
9294 if(useSet) el.setAttribute(attr, o[attr]);
9295 else el[attr] = o[attr];
9299 Roo.DomHelper.applyStyles(el, o.style);
9305 * Convenience method for constructing a KeyMap
9306 * @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:
9307 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9308 * @param {Function} fn The function to call
9309 * @param {Object} scope (optional) The scope of the function
9310 * @return {Roo.KeyMap} The KeyMap created
9312 addKeyListener : function(key, fn, scope){
9314 if(typeof key != "object" || key instanceof Array){
9330 return new Roo.KeyMap(this, config);
9334 * Creates a KeyMap for this element
9335 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9336 * @return {Roo.KeyMap} The KeyMap created
9338 addKeyMap : function(config){
9339 return new Roo.KeyMap(this, config);
9343 * Returns true if this element is scrollable.
9346 isScrollable : function(){
9348 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9352 * 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().
9353 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9354 * @param {Number} value The new scroll value
9355 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9356 * @return {Element} this
9359 scrollTo : function(side, value, animate){
9360 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9362 this.dom[prop] = value;
9364 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9365 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9371 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9372 * within this element's scrollable range.
9373 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9374 * @param {Number} distance How far to scroll the element in pixels
9375 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9376 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9377 * was scrolled as far as it could go.
9379 scroll : function(direction, distance, animate){
9380 if(!this.isScrollable()){
9384 var l = el.scrollLeft, t = el.scrollTop;
9385 var w = el.scrollWidth, h = el.scrollHeight;
9386 var cw = el.clientWidth, ch = el.clientHeight;
9387 direction = direction.toLowerCase();
9388 var scrolled = false;
9389 var a = this.preanim(arguments, 2);
9394 var v = Math.min(l + distance, w-cw);
9395 this.scrollTo("left", v, a);
9402 var v = Math.max(l - distance, 0);
9403 this.scrollTo("left", v, a);
9411 var v = Math.max(t - distance, 0);
9412 this.scrollTo("top", v, a);
9420 var v = Math.min(t + distance, h-ch);
9421 this.scrollTo("top", v, a);
9430 * Translates the passed page coordinates into left/top css values for this element
9431 * @param {Number/Array} x The page x or an array containing [x, y]
9432 * @param {Number} y The page y
9433 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9435 translatePoints : function(x, y){
9436 if(typeof x == 'object' || x instanceof Array){
9439 var p = this.getStyle('position');
9440 var o = this.getXY();
9442 var l = parseInt(this.getStyle('left'), 10);
9443 var t = parseInt(this.getStyle('top'), 10);
9446 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9449 t = (p == "relative") ? 0 : this.dom.offsetTop;
9452 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9456 * Returns the current scroll position of the element.
9457 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9459 getScroll : function(){
9460 var d = this.dom, doc = document;
9461 if(d == doc || d == doc.body){
9462 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9463 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9464 return {left: l, top: t};
9466 return {left: d.scrollLeft, top: d.scrollTop};
9471 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9472 * are convert to standard 6 digit hex color.
9473 * @param {String} attr The css attribute
9474 * @param {String} defaultValue The default value to use when a valid color isn't found
9475 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9478 getColor : function(attr, defaultValue, prefix){
9479 var v = this.getStyle(attr);
9480 if(!v || v == "transparent" || v == "inherit") {
9481 return defaultValue;
9483 var color = typeof prefix == "undefined" ? "#" : prefix;
9484 if(v.substr(0, 4) == "rgb("){
9485 var rvs = v.slice(4, v.length -1).split(",");
9486 for(var i = 0; i < 3; i++){
9487 var h = parseInt(rvs[i]).toString(16);
9494 if(v.substr(0, 1) == "#"){
9496 for(var i = 1; i < 4; i++){
9497 var c = v.charAt(i);
9500 }else if(v.length == 7){
9501 color += v.substr(1);
9505 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9509 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9510 * gradient background, rounded corners and a 4-way shadow.
9511 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9512 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9513 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9514 * @return {Roo.Element} this
9516 boxWrap : function(cls){
9517 cls = cls || 'x-box';
9518 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9519 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9524 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9525 * @param {String} namespace The namespace in which to look for the attribute
9526 * @param {String} name The attribute name
9527 * @return {String} The attribute value
9529 getAttributeNS : Roo.isIE ? function(ns, name){
9531 var type = typeof d[ns+":"+name];
9532 if(type != 'undefined' && type != 'unknown'){
9533 return d[ns+":"+name];
9536 } : function(ns, name){
9538 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9542 var ep = El.prototype;
9545 * Appends an event handler (Shorthand for addListener)
9546 * @param {String} eventName The type of event to append
9547 * @param {Function} fn The method the event invokes
9548 * @param {Object} scope (optional) The scope (this object) of the fn
9549 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9552 ep.on = ep.addListener;
9554 ep.mon = ep.addListener;
9557 * Removes an event handler from this element (shorthand for removeListener)
9558 * @param {String} eventName the type of event to remove
9559 * @param {Function} fn the method the event invokes
9560 * @return {Roo.Element} this
9563 ep.un = ep.removeListener;
9566 * true to automatically adjust width and height settings for box-model issues (default to true)
9568 ep.autoBoxAdjust = true;
9571 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9574 El.addUnits = function(v, defaultUnit){
9575 if(v === "" || v == "auto"){
9578 if(v === undefined){
9581 if(typeof v == "number" || !El.unitPattern.test(v)){
9582 return v + (defaultUnit || 'px');
9587 // special markup used throughout Roo when box wrapping elements
9588 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>';
9590 * Visibility mode constant - Use visibility to hide element
9596 * Visibility mode constant - Use display to hide element
9602 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9603 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9604 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9616 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9617 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9618 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9619 * @return {Element} The Element object
9622 El.get = function(el){
9624 if(!el){ return null; }
9625 if(typeof el == "string"){ // element id
9626 if(!(elm = document.getElementById(el))){
9629 if(ex = El.cache[el]){
9632 ex = El.cache[el] = new El(elm);
9635 }else if(el.tagName){ // dom element
9639 if(ex = El.cache[id]){
9642 ex = El.cache[id] = new El(el);
9645 }else if(el instanceof El){
9647 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9648 // catch case where it hasn't been appended
9649 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9652 }else if(el.isComposite){
9654 }else if(el instanceof Array){
9655 return El.select(el);
9656 }else if(el == document){
9657 // create a bogus element object representing the document object
9659 var f = function(){};
9660 f.prototype = El.prototype;
9662 docEl.dom = document;
9670 El.uncache = function(el){
9671 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9673 delete El.cache[a[i].id || a[i]];
9679 // Garbage collection - uncache elements/purge listeners on orphaned elements
9680 // so we don't hold a reference and cause the browser to retain them
9681 El.garbageCollect = function(){
9682 if(!Roo.enableGarbageCollector){
9683 clearInterval(El.collectorThread);
9686 for(var eid in El.cache){
9687 var el = El.cache[eid], d = el.dom;
9688 // -------------------------------------------------------
9689 // Determining what is garbage:
9690 // -------------------------------------------------------
9692 // dom node is null, definitely garbage
9693 // -------------------------------------------------------
9695 // no parentNode == direct orphan, definitely garbage
9696 // -------------------------------------------------------
9697 // !d.offsetParent && !document.getElementById(eid)
9698 // display none elements have no offsetParent so we will
9699 // also try to look it up by it's id. However, check
9700 // offsetParent first so we don't do unneeded lookups.
9701 // This enables collection of elements that are not orphans
9702 // directly, but somewhere up the line they have an orphan
9704 // -------------------------------------------------------
9705 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9706 delete El.cache[eid];
9707 if(d && Roo.enableListenerCollection){
9713 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9717 El.Flyweight = function(dom){
9720 El.Flyweight.prototype = El.prototype;
9722 El._flyweights = {};
9724 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9725 * the dom node can be overwritten by other code.
9726 * @param {String/HTMLElement} el The dom node or id
9727 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9728 * prevent conflicts (e.g. internally Roo uses "_internal")
9730 * @return {Element} The shared Element object
9732 El.fly = function(el, named){
9733 named = named || '_global';
9734 el = Roo.getDom(el);
9738 if(!El._flyweights[named]){
9739 El._flyweights[named] = new El.Flyweight();
9741 El._flyweights[named].dom = el;
9742 return El._flyweights[named];
9746 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9747 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9748 * Shorthand of {@link Roo.Element#get}
9749 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9750 * @return {Element} The Element object
9756 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9757 * the dom node can be overwritten by other code.
9758 * Shorthand of {@link Roo.Element#fly}
9759 * @param {String/HTMLElement} el The dom node or id
9760 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9761 * prevent conflicts (e.g. internally Roo uses "_internal")
9763 * @return {Element} The shared Element object
9769 // speedy lookup for elements never to box adjust
9770 var noBoxAdjust = Roo.isStrict ? {
9773 input:1, select:1, textarea:1
9775 if(Roo.isIE || Roo.isGecko){
9776 noBoxAdjust['button'] = 1;
9780 Roo.EventManager.on(window, 'unload', function(){
9782 delete El._flyweights;
9790 Roo.Element.selectorFunction = Roo.DomQuery.select;
9793 Roo.Element.select = function(selector, unique, root){
9795 if(typeof selector == "string"){
9796 els = Roo.Element.selectorFunction(selector, root);
9797 }else if(selector.length !== undefined){
9800 throw "Invalid selector";
9802 if(unique === true){
9803 return new Roo.CompositeElement(els);
9805 return new Roo.CompositeElementLite(els);
9809 * Selects elements based on the passed CSS selector to enable working on them as 1.
9810 * @param {String/Array} selector The CSS selector or an array of elements
9811 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9812 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9813 * @return {CompositeElementLite/CompositeElement}
9817 Roo.select = Roo.Element.select;
9834 * Ext JS Library 1.1.1
9835 * Copyright(c) 2006-2007, Ext JS, LLC.
9837 * Originally Released Under LGPL - original licence link has changed is not relivant.
9840 * <script type="text/javascript">
9845 //Notifies Element that fx methods are available
9846 Roo.enableFx = true;
9850 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9851 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9852 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9853 * Element effects to work.</p><br/>
9855 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9856 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9857 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9858 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9859 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9860 * expected results and should be done with care.</p><br/>
9862 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9863 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9866 ----- -----------------------------
9867 tl The top left corner
9868 t The center of the top edge
9869 tr The top right corner
9870 l The center of the left edge
9871 r The center of the right edge
9872 bl The bottom left corner
9873 b The center of the bottom edge
9874 br The bottom right corner
9876 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9877 * below are common options that can be passed to any Fx method.</b>
9878 * @cfg {Function} callback A function called when the effect is finished
9879 * @cfg {Object} scope The scope of the effect function
9880 * @cfg {String} easing A valid Easing value for the effect
9881 * @cfg {String} afterCls A css class to apply after the effect
9882 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9883 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9884 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9885 * effects that end with the element being visually hidden, ignored otherwise)
9886 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9887 * a function which returns such a specification that will be applied to the Element after the effect finishes
9888 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9889 * @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
9890 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9894 * Slides the element into view. An anchor point can be optionally passed to set the point of
9895 * origin for the slide effect. This function automatically handles wrapping the element with
9896 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9899 // default: slide the element in from the top
9902 // custom: slide the element in from the right with a 2-second duration
9903 el.slideIn('r', { duration: 2 });
9905 // common config options shown with default values
9911 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9912 * @param {Object} options (optional) Object literal with any of the Fx config options
9913 * @return {Roo.Element} The Element
9915 slideIn : function(anchor, o){
9916 var el = this.getFxEl();
9919 el.queueFx(o, function(){
9921 anchor = anchor || "t";
9923 // fix display to visibility
9926 // restore values after effect
9927 var r = this.getFxRestore();
9928 var b = this.getBox();
9929 // fixed size for slide
9933 var wrap = this.fxWrap(r.pos, o, "hidden");
9935 var st = this.dom.style;
9936 st.visibility = "visible";
9937 st.position = "absolute";
9939 // clear out temp styles after slide and unwrap
9940 var after = function(){
9941 el.fxUnwrap(wrap, r.pos, o);
9943 st.height = r.height;
9946 // time to calc the positions
9947 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9949 switch(anchor.toLowerCase()){
9951 wrap.setSize(b.width, 0);
9952 st.left = st.bottom = "0";
9956 wrap.setSize(0, b.height);
9957 st.right = st.top = "0";
9961 wrap.setSize(0, b.height);
9963 st.left = st.top = "0";
9964 a = {width: bw, points: pt};
9967 wrap.setSize(b.width, 0);
9968 wrap.setY(b.bottom);
9969 st.left = st.top = "0";
9970 a = {height: bh, points: pt};
9974 st.right = st.bottom = "0";
9975 a = {width: bw, height: bh};
9979 wrap.setY(b.y+b.height);
9980 st.right = st.top = "0";
9981 a = {width: bw, height: bh, points: pt};
9985 wrap.setXY([b.right, b.bottom]);
9986 st.left = st.top = "0";
9987 a = {width: bw, height: bh, points: pt};
9991 wrap.setX(b.x+b.width);
9992 st.left = st.bottom = "0";
9993 a = {width: bw, height: bh, points: pt};
9996 this.dom.style.visibility = "visible";
9999 arguments.callee.anim = wrap.fxanim(a,
10009 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10010 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10011 * 'hidden') but block elements will still take up space in the document. The element must be removed
10012 * from the DOM using the 'remove' config option if desired. This function automatically handles
10013 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10016 // default: slide the element out to the top
10019 // custom: slide the element out to the right with a 2-second duration
10020 el.slideOut('r', { duration: 2 });
10022 // common config options shown with default values
10030 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10031 * @param {Object} options (optional) Object literal with any of the Fx config options
10032 * @return {Roo.Element} The Element
10034 slideOut : function(anchor, o){
10035 var el = this.getFxEl();
10038 el.queueFx(o, function(){
10040 anchor = anchor || "t";
10042 // restore values after effect
10043 var r = this.getFxRestore();
10045 var b = this.getBox();
10046 // fixed size for slide
10050 var wrap = this.fxWrap(r.pos, o, "visible");
10052 var st = this.dom.style;
10053 st.visibility = "visible";
10054 st.position = "absolute";
10058 var after = function(){
10060 el.setDisplayed(false);
10065 el.fxUnwrap(wrap, r.pos, o);
10067 st.width = r.width;
10068 st.height = r.height;
10073 var a, zero = {to: 0};
10074 switch(anchor.toLowerCase()){
10076 st.left = st.bottom = "0";
10077 a = {height: zero};
10080 st.right = st.top = "0";
10084 st.left = st.top = "0";
10085 a = {width: zero, points: {to:[b.right, b.y]}};
10088 st.left = st.top = "0";
10089 a = {height: zero, points: {to:[b.x, b.bottom]}};
10092 st.right = st.bottom = "0";
10093 a = {width: zero, height: zero};
10096 st.right = st.top = "0";
10097 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10100 st.left = st.top = "0";
10101 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10104 st.left = st.bottom = "0";
10105 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10109 arguments.callee.anim = wrap.fxanim(a,
10119 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10120 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10121 * The element must be removed from the DOM using the 'remove' config option if desired.
10127 // common config options shown with default values
10135 * @param {Object} options (optional) Object literal with any of the Fx config options
10136 * @return {Roo.Element} The Element
10138 puff : function(o){
10139 var el = this.getFxEl();
10142 el.queueFx(o, function(){
10143 this.clearOpacity();
10146 // restore values after effect
10147 var r = this.getFxRestore();
10148 var st = this.dom.style;
10150 var after = function(){
10152 el.setDisplayed(false);
10159 el.setPositioning(r.pos);
10160 st.width = r.width;
10161 st.height = r.height;
10166 var width = this.getWidth();
10167 var height = this.getHeight();
10169 arguments.callee.anim = this.fxanim({
10170 width : {to: this.adjustWidth(width * 2)},
10171 height : {to: this.adjustHeight(height * 2)},
10172 points : {by: [-(width * .5), -(height * .5)]},
10174 fontSize: {to:200, unit: "%"}
10185 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10186 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10187 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10193 // all config options shown with default values
10201 * @param {Object} options (optional) Object literal with any of the Fx config options
10202 * @return {Roo.Element} The Element
10204 switchOff : function(o){
10205 var el = this.getFxEl();
10208 el.queueFx(o, function(){
10209 this.clearOpacity();
10212 // restore values after effect
10213 var r = this.getFxRestore();
10214 var st = this.dom.style;
10216 var after = function(){
10218 el.setDisplayed(false);
10224 el.setPositioning(r.pos);
10225 st.width = r.width;
10226 st.height = r.height;
10231 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10232 this.clearOpacity();
10236 points:{by:[0, this.getHeight() * .5]}
10237 }, o, 'motion', 0.3, 'easeIn', after);
10238 }).defer(100, this);
10245 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10246 * changed using the "attr" config option) and then fading back to the original color. If no original
10247 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10250 // default: highlight background to yellow
10253 // custom: highlight foreground text to blue for 2 seconds
10254 el.highlight("0000ff", { attr: 'color', duration: 2 });
10256 // common config options shown with default values
10257 el.highlight("ffff9c", {
10258 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10259 endColor: (current color) or "ffffff",
10264 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10265 * @param {Object} options (optional) Object literal with any of the Fx config options
10266 * @return {Roo.Element} The Element
10268 highlight : function(color, o){
10269 var el = this.getFxEl();
10272 el.queueFx(o, function(){
10273 color = color || "ffff9c";
10274 attr = o.attr || "backgroundColor";
10276 this.clearOpacity();
10279 var origColor = this.getColor(attr);
10280 var restoreColor = this.dom.style[attr];
10281 endColor = (o.endColor || origColor) || "ffffff";
10283 var after = function(){
10284 el.dom.style[attr] = restoreColor;
10289 a[attr] = {from: color, to: endColor};
10290 arguments.callee.anim = this.fxanim(a,
10300 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10303 // default: a single light blue ripple
10306 // custom: 3 red ripples lasting 3 seconds total
10307 el.frame("ff0000", 3, { duration: 3 });
10309 // common config options shown with default values
10310 el.frame("C3DAF9", 1, {
10311 duration: 1 //duration of entire animation (not each individual ripple)
10312 // Note: Easing is not configurable and will be ignored if included
10315 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10316 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10317 * @param {Object} options (optional) Object literal with any of the Fx config options
10318 * @return {Roo.Element} The Element
10320 frame : function(color, count, o){
10321 var el = this.getFxEl();
10324 el.queueFx(o, function(){
10325 color = color || "#C3DAF9";
10326 if(color.length == 6){
10327 color = "#" + color;
10329 count = count || 1;
10330 duration = o.duration || 1;
10333 var b = this.getBox();
10334 var animFn = function(){
10335 var proxy = this.createProxy({
10338 visbility:"hidden",
10339 position:"absolute",
10340 "z-index":"35000", // yee haw
10341 border:"0px solid " + color
10344 var scale = Roo.isBorderBox ? 2 : 1;
10346 top:{from:b.y, to:b.y - 20},
10347 left:{from:b.x, to:b.x - 20},
10348 borderWidth:{from:0, to:10},
10349 opacity:{from:1, to:0},
10350 height:{from:b.height, to:(b.height + (20*scale))},
10351 width:{from:b.width, to:(b.width + (20*scale))}
10352 }, duration, function(){
10356 animFn.defer((duration/2)*1000, this);
10367 * Creates a pause before any subsequent queued effects begin. If there are
10368 * no effects queued after the pause it will have no effect.
10373 * @param {Number} seconds The length of time to pause (in seconds)
10374 * @return {Roo.Element} The Element
10376 pause : function(seconds){
10377 var el = this.getFxEl();
10380 el.queueFx(o, function(){
10381 setTimeout(function(){
10383 }, seconds * 1000);
10389 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10390 * using the "endOpacity" config option.
10393 // default: fade in from opacity 0 to 100%
10396 // custom: fade in from opacity 0 to 75% over 2 seconds
10397 el.fadeIn({ endOpacity: .75, duration: 2});
10399 // common config options shown with default values
10401 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10406 * @param {Object} options (optional) Object literal with any of the Fx config options
10407 * @return {Roo.Element} The Element
10409 fadeIn : function(o){
10410 var el = this.getFxEl();
10412 el.queueFx(o, function(){
10413 this.setOpacity(0);
10415 this.dom.style.visibility = 'visible';
10416 var to = o.endOpacity || 1;
10417 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10418 o, null, .5, "easeOut", function(){
10420 this.clearOpacity();
10429 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10430 * using the "endOpacity" config option.
10433 // default: fade out from the element's current opacity to 0
10436 // custom: fade out from the element's current opacity to 25% over 2 seconds
10437 el.fadeOut({ endOpacity: .25, duration: 2});
10439 // common config options shown with default values
10441 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10448 * @param {Object} options (optional) Object literal with any of the Fx config options
10449 * @return {Roo.Element} The Element
10451 fadeOut : function(o){
10452 var el = this.getFxEl();
10454 el.queueFx(o, function(){
10455 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10456 o, null, .5, "easeOut", function(){
10457 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10458 this.dom.style.display = "none";
10460 this.dom.style.visibility = "hidden";
10462 this.clearOpacity();
10470 * Animates the transition of an element's dimensions from a starting height/width
10471 * to an ending height/width.
10474 // change height and width to 100x100 pixels
10475 el.scale(100, 100);
10477 // common config options shown with default values. The height and width will default to
10478 // the element's existing values if passed as null.
10481 [element's height], {
10486 * @param {Number} width The new width (pass undefined to keep the original width)
10487 * @param {Number} height The new height (pass undefined to keep the original height)
10488 * @param {Object} options (optional) Object literal with any of the Fx config options
10489 * @return {Roo.Element} The Element
10491 scale : function(w, h, o){
10492 this.shift(Roo.apply({}, o, {
10500 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10501 * Any of these properties not specified in the config object will not be changed. This effect
10502 * requires that at least one new dimension, position or opacity setting must be passed in on
10503 * the config object in order for the function to have any effect.
10506 // slide the element horizontally to x position 200 while changing the height and opacity
10507 el.shift({ x: 200, height: 50, opacity: .8 });
10509 // common config options shown with default values.
10511 width: [element's width],
10512 height: [element's height],
10513 x: [element's x position],
10514 y: [element's y position],
10515 opacity: [element's opacity],
10520 * @param {Object} options Object literal with any of the Fx config options
10521 * @return {Roo.Element} The Element
10523 shift : function(o){
10524 var el = this.getFxEl();
10526 el.queueFx(o, function(){
10527 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10528 if(w !== undefined){
10529 a.width = {to: this.adjustWidth(w)};
10531 if(h !== undefined){
10532 a.height = {to: this.adjustHeight(h)};
10534 if(x !== undefined || y !== undefined){
10536 x !== undefined ? x : this.getX(),
10537 y !== undefined ? y : this.getY()
10540 if(op !== undefined){
10541 a.opacity = {to: op};
10543 if(o.xy !== undefined){
10544 a.points = {to: o.xy};
10546 arguments.callee.anim = this.fxanim(a,
10547 o, 'motion', .35, "easeOut", function(){
10555 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10556 * ending point of the effect.
10559 // default: slide the element downward while fading out
10562 // custom: slide the element out to the right with a 2-second duration
10563 el.ghost('r', { duration: 2 });
10565 // common config options shown with default values
10573 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10574 * @param {Object} options (optional) Object literal with any of the Fx config options
10575 * @return {Roo.Element} The Element
10577 ghost : function(anchor, o){
10578 var el = this.getFxEl();
10581 el.queueFx(o, function(){
10582 anchor = anchor || "b";
10584 // restore values after effect
10585 var r = this.getFxRestore();
10586 var w = this.getWidth(),
10587 h = this.getHeight();
10589 var st = this.dom.style;
10591 var after = function(){
10593 el.setDisplayed(false);
10599 el.setPositioning(r.pos);
10600 st.width = r.width;
10601 st.height = r.height;
10606 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10607 switch(anchor.toLowerCase()){
10634 arguments.callee.anim = this.fxanim(a,
10644 * Ensures that all effects queued after syncFx is called on the element are
10645 * run concurrently. This is the opposite of {@link #sequenceFx}.
10646 * @return {Roo.Element} The Element
10648 syncFx : function(){
10649 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10658 * Ensures that all effects queued after sequenceFx is called on the element are
10659 * run in sequence. This is the opposite of {@link #syncFx}.
10660 * @return {Roo.Element} The Element
10662 sequenceFx : function(){
10663 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10665 concurrent : false,
10672 nextFx : function(){
10673 var ef = this.fxQueue[0];
10680 * Returns true if the element has any effects actively running or queued, else returns false.
10681 * @return {Boolean} True if element has active effects, else false
10683 hasActiveFx : function(){
10684 return this.fxQueue && this.fxQueue[0];
10688 * Stops any running effects and clears the element's internal effects queue if it contains
10689 * any additional effects that haven't started yet.
10690 * @return {Roo.Element} The Element
10692 stopFx : function(){
10693 if(this.hasActiveFx()){
10694 var cur = this.fxQueue[0];
10695 if(cur && cur.anim && cur.anim.isAnimated()){
10696 this.fxQueue = [cur]; // clear out others
10697 cur.anim.stop(true);
10704 beforeFx : function(o){
10705 if(this.hasActiveFx() && !o.concurrent){
10716 * Returns true if the element is currently blocking so that no other effect can be queued
10717 * until this effect is finished, else returns false if blocking is not set. This is commonly
10718 * used to ensure that an effect initiated by a user action runs to completion prior to the
10719 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10720 * @return {Boolean} True if blocking, else false
10722 hasFxBlock : function(){
10723 var q = this.fxQueue;
10724 return q && q[0] && q[0].block;
10728 queueFx : function(o, fn){
10732 if(!this.hasFxBlock()){
10733 Roo.applyIf(o, this.fxDefaults);
10735 var run = this.beforeFx(o);
10736 fn.block = o.block;
10737 this.fxQueue.push(fn);
10749 fxWrap : function(pos, o, vis){
10751 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10754 wrapXY = this.getXY();
10756 var div = document.createElement("div");
10757 div.style.visibility = vis;
10758 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10759 wrap.setPositioning(pos);
10760 if(wrap.getStyle("position") == "static"){
10761 wrap.position("relative");
10763 this.clearPositioning('auto');
10765 wrap.dom.appendChild(this.dom);
10767 wrap.setXY(wrapXY);
10774 fxUnwrap : function(wrap, pos, o){
10775 this.clearPositioning();
10776 this.setPositioning(pos);
10778 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10784 getFxRestore : function(){
10785 var st = this.dom.style;
10786 return {pos: this.getPositioning(), width: st.width, height : st.height};
10790 afterFx : function(o){
10792 this.applyStyles(o.afterStyle);
10795 this.addClass(o.afterCls);
10797 if(o.remove === true){
10800 Roo.callback(o.callback, o.scope, [this]);
10802 this.fxQueue.shift();
10808 getFxEl : function(){ // support for composite element fx
10809 return Roo.get(this.dom);
10813 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10814 animType = animType || 'run';
10816 var anim = Roo.lib.Anim[animType](
10818 (opt.duration || defaultDur) || .35,
10819 (opt.easing || defaultEase) || 'easeOut',
10821 Roo.callback(cb, this);
10830 // backwords compat
10831 Roo.Fx.resize = Roo.Fx.scale;
10833 //When included, Roo.Fx is automatically applied to Element so that all basic
10834 //effects are available directly via the Element API
10835 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10837 * Ext JS Library 1.1.1
10838 * Copyright(c) 2006-2007, Ext JS, LLC.
10840 * Originally Released Under LGPL - original licence link has changed is not relivant.
10843 * <script type="text/javascript">
10848 * @class Roo.CompositeElement
10849 * Standard composite class. Creates a Roo.Element for every element in the collection.
10851 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10852 * actions will be performed on all the elements in this collection.</b>
10854 * All methods return <i>this</i> and can be chained.
10856 var els = Roo.select("#some-el div.some-class", true);
10857 // or select directly from an existing element
10858 var el = Roo.get('some-el');
10859 el.select('div.some-class', true);
10861 els.setWidth(100); // all elements become 100 width
10862 els.hide(true); // all elements fade out and hide
10864 els.setWidth(100).hide(true);
10867 Roo.CompositeElement = function(els){
10868 this.elements = [];
10869 this.addElements(els);
10871 Roo.CompositeElement.prototype = {
10873 addElements : function(els){
10874 if(!els) return this;
10875 if(typeof els == "string"){
10876 els = Roo.Element.selectorFunction(els);
10878 var yels = this.elements;
10879 var index = yels.length-1;
10880 for(var i = 0, len = els.length; i < len; i++) {
10881 yels[++index] = Roo.get(els[i]);
10887 * Clears this composite and adds the elements returned by the passed selector.
10888 * @param {String/Array} els A string CSS selector, an array of elements or an element
10889 * @return {CompositeElement} this
10891 fill : function(els){
10892 this.elements = [];
10898 * Filters this composite to only elements that match the passed selector.
10899 * @param {String} selector A string CSS selector
10900 * @return {CompositeElement} this
10902 filter : function(selector){
10904 this.each(function(el){
10905 if(el.is(selector)){
10906 els[els.length] = el.dom;
10913 invoke : function(fn, args){
10914 var els = this.elements;
10915 for(var i = 0, len = els.length; i < len; i++) {
10916 Roo.Element.prototype[fn].apply(els[i], args);
10921 * Adds elements to this composite.
10922 * @param {String/Array} els A string CSS selector, an array of elements or an element
10923 * @return {CompositeElement} this
10925 add : function(els){
10926 if(typeof els == "string"){
10927 this.addElements(Roo.Element.selectorFunction(els));
10928 }else if(els.length !== undefined){
10929 this.addElements(els);
10931 this.addElements([els]);
10936 * Calls the passed function passing (el, this, index) for each element in this composite.
10937 * @param {Function} fn The function to call
10938 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10939 * @return {CompositeElement} this
10941 each : function(fn, scope){
10942 var els = this.elements;
10943 for(var i = 0, len = els.length; i < len; i++){
10944 if(fn.call(scope || els[i], els[i], this, i) === false) {
10952 * Returns the Element object at the specified index
10953 * @param {Number} index
10954 * @return {Roo.Element}
10956 item : function(index){
10957 return this.elements[index] || null;
10961 * Returns the first Element
10962 * @return {Roo.Element}
10964 first : function(){
10965 return this.item(0);
10969 * Returns the last Element
10970 * @return {Roo.Element}
10973 return this.item(this.elements.length-1);
10977 * Returns the number of elements in this composite
10980 getCount : function(){
10981 return this.elements.length;
10985 * Returns true if this composite contains the passed element
10988 contains : function(el){
10989 return this.indexOf(el) !== -1;
10993 * Returns true if this composite contains the passed element
10996 indexOf : function(el){
10997 return this.elements.indexOf(Roo.get(el));
11002 * Removes the specified element(s).
11003 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11004 * or an array of any of those.
11005 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11006 * @return {CompositeElement} this
11008 removeElement : function(el, removeDom){
11009 if(el instanceof Array){
11010 for(var i = 0, len = el.length; i < len; i++){
11011 this.removeElement(el[i]);
11015 var index = typeof el == 'number' ? el : this.indexOf(el);
11018 var d = this.elements[index];
11022 d.parentNode.removeChild(d);
11025 this.elements.splice(index, 1);
11031 * Replaces the specified element with the passed element.
11032 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11034 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11035 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11036 * @return {CompositeElement} this
11038 replaceElement : function(el, replacement, domReplace){
11039 var index = typeof el == 'number' ? el : this.indexOf(el);
11042 this.elements[index].replaceWith(replacement);
11044 this.elements.splice(index, 1, Roo.get(replacement))
11051 * Removes all elements.
11053 clear : function(){
11054 this.elements = [];
11058 Roo.CompositeElement.createCall = function(proto, fnName){
11059 if(!proto[fnName]){
11060 proto[fnName] = function(){
11061 return this.invoke(fnName, arguments);
11065 for(var fnName in Roo.Element.prototype){
11066 if(typeof Roo.Element.prototype[fnName] == "function"){
11067 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11073 * Ext JS Library 1.1.1
11074 * Copyright(c) 2006-2007, Ext JS, LLC.
11076 * Originally Released Under LGPL - original licence link has changed is not relivant.
11079 * <script type="text/javascript">
11083 * @class Roo.CompositeElementLite
11084 * @extends Roo.CompositeElement
11085 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11087 var els = Roo.select("#some-el div.some-class");
11088 // or select directly from an existing element
11089 var el = Roo.get('some-el');
11090 el.select('div.some-class');
11092 els.setWidth(100); // all elements become 100 width
11093 els.hide(true); // all elements fade out and hide
11095 els.setWidth(100).hide(true);
11096 </code></pre><br><br>
11097 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11098 * actions will be performed on all the elements in this collection.</b>
11100 Roo.CompositeElementLite = function(els){
11101 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11102 this.el = new Roo.Element.Flyweight();
11104 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11105 addElements : function(els){
11107 if(els instanceof Array){
11108 this.elements = this.elements.concat(els);
11110 var yels = this.elements;
11111 var index = yels.length-1;
11112 for(var i = 0, len = els.length; i < len; i++) {
11113 yels[++index] = els[i];
11119 invoke : function(fn, args){
11120 var els = this.elements;
11122 for(var i = 0, len = els.length; i < len; i++) {
11124 Roo.Element.prototype[fn].apply(el, args);
11129 * Returns a flyweight Element of the dom element object at the specified index
11130 * @param {Number} index
11131 * @return {Roo.Element}
11133 item : function(index){
11134 if(!this.elements[index]){
11137 this.el.dom = this.elements[index];
11141 // fixes scope with flyweight
11142 addListener : function(eventName, handler, scope, opt){
11143 var els = this.elements;
11144 for(var i = 0, len = els.length; i < len; i++) {
11145 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11151 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11152 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11153 * a reference to the dom node, use el.dom.</b>
11154 * @param {Function} fn The function to call
11155 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11156 * @return {CompositeElement} this
11158 each : function(fn, scope){
11159 var els = this.elements;
11161 for(var i = 0, len = els.length; i < len; i++){
11163 if(fn.call(scope || el, el, this, i) === false){
11170 indexOf : function(el){
11171 return this.elements.indexOf(Roo.getDom(el));
11174 replaceElement : function(el, replacement, domReplace){
11175 var index = typeof el == 'number' ? el : this.indexOf(el);
11177 replacement = Roo.getDom(replacement);
11179 var d = this.elements[index];
11180 d.parentNode.insertBefore(replacement, d);
11181 d.parentNode.removeChild(d);
11183 this.elements.splice(index, 1, replacement);
11188 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11192 * Ext JS Library 1.1.1
11193 * Copyright(c) 2006-2007, Ext JS, LLC.
11195 * Originally Released Under LGPL - original licence link has changed is not relivant.
11198 * <script type="text/javascript">
11204 * @class Roo.data.Connection
11205 * @extends Roo.util.Observable
11206 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11207 * either to a configured URL, or to a URL specified at request time.<br><br>
11209 * Requests made by this class are asynchronous, and will return immediately. No data from
11210 * the server will be available to the statement immediately following the {@link #request} call.
11211 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11213 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11214 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11215 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11216 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11217 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11218 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11219 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11220 * standard DOM methods.
11222 * @param {Object} config a configuration object.
11224 Roo.data.Connection = function(config){
11225 Roo.apply(this, config);
11228 * @event beforerequest
11229 * Fires before a network request is made to retrieve a data object.
11230 * @param {Connection} conn This Connection object.
11231 * @param {Object} options The options config object passed to the {@link #request} method.
11233 "beforerequest" : true,
11235 * @event requestcomplete
11236 * Fires if the request was successfully completed.
11237 * @param {Connection} conn This Connection object.
11238 * @param {Object} response The XHR object containing the response data.
11239 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11240 * @param {Object} options The options config object passed to the {@link #request} method.
11242 "requestcomplete" : true,
11244 * @event requestexception
11245 * Fires if an error HTTP status was returned from the server.
11246 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11247 * @param {Connection} conn This Connection object.
11248 * @param {Object} response The XHR object containing the response data.
11249 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11250 * @param {Object} options The options config object passed to the {@link #request} method.
11252 "requestexception" : true
11254 Roo.data.Connection.superclass.constructor.call(this);
11257 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11259 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11262 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11263 * extra parameters to each request made by this object. (defaults to undefined)
11266 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11267 * to each request made by this object. (defaults to undefined)
11270 * @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)
11273 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11277 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11283 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11286 disableCaching: true,
11289 * Sends an HTTP request to a remote server.
11290 * @param {Object} options An object which may contain the following properties:<ul>
11291 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11292 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11293 * request, a url encoded string or a function to call to get either.</li>
11294 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11295 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11296 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11297 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11298 * <li>options {Object} The parameter to the request call.</li>
11299 * <li>success {Boolean} True if the request succeeded.</li>
11300 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11302 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11303 * The callback is passed the following parameters:<ul>
11304 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11305 * <li>options {Object} The parameter to the request call.</li>
11307 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11308 * The callback is passed the following parameters:<ul>
11309 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11310 * <li>options {Object} The parameter to the request call.</li>
11312 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11313 * for the callback function. Defaults to the browser window.</li>
11314 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11315 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11316 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11317 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11318 * params for the post data. Any params will be appended to the URL.</li>
11319 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11321 * @return {Number} transactionId
11323 request : function(o){
11324 if(this.fireEvent("beforerequest", this, o) !== false){
11327 if(typeof p == "function"){
11328 p = p.call(o.scope||window, o);
11330 if(typeof p == "object"){
11331 p = Roo.urlEncode(o.params);
11333 if(this.extraParams){
11334 var extras = Roo.urlEncode(this.extraParams);
11335 p = p ? (p + '&' + extras) : extras;
11338 var url = o.url || this.url;
11339 if(typeof url == 'function'){
11340 url = url.call(o.scope||window, o);
11344 var form = Roo.getDom(o.form);
11345 url = url || form.action;
11347 var enctype = form.getAttribute("enctype");
11348 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11349 return this.doFormUpload(o, p, url);
11351 var f = Roo.lib.Ajax.serializeForm(form);
11352 p = p ? (p + '&' + f) : f;
11355 var hs = o.headers;
11356 if(this.defaultHeaders){
11357 hs = Roo.apply(hs || {}, this.defaultHeaders);
11364 success: this.handleResponse,
11365 failure: this.handleFailure,
11367 argument: {options: o},
11368 timeout : this.timeout
11371 var method = o.method||this.method||(p ? "POST" : "GET");
11373 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11374 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11377 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11381 }else if(this.autoAbort !== false){
11385 if((method == 'GET' && p) || o.xmlData){
11386 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11389 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11390 return this.transId;
11392 Roo.callback(o.callback, o.scope, [o, null, null]);
11398 * Determine whether this object has a request outstanding.
11399 * @param {Number} transactionId (Optional) defaults to the last transaction
11400 * @return {Boolean} True if there is an outstanding request.
11402 isLoading : function(transId){
11404 return Roo.lib.Ajax.isCallInProgress(transId);
11406 return this.transId ? true : false;
11411 * Aborts any outstanding request.
11412 * @param {Number} transactionId (Optional) defaults to the last transaction
11414 abort : function(transId){
11415 if(transId || this.isLoading()){
11416 Roo.lib.Ajax.abort(transId || this.transId);
11421 handleResponse : function(response){
11422 this.transId = false;
11423 var options = response.argument.options;
11424 response.argument = options ? options.argument : null;
11425 this.fireEvent("requestcomplete", this, response, options);
11426 Roo.callback(options.success, options.scope, [response, options]);
11427 Roo.callback(options.callback, options.scope, [options, true, response]);
11431 handleFailure : function(response, e){
11432 this.transId = false;
11433 var options = response.argument.options;
11434 response.argument = options ? options.argument : null;
11435 this.fireEvent("requestexception", this, response, options, e);
11436 Roo.callback(options.failure, options.scope, [response, options]);
11437 Roo.callback(options.callback, options.scope, [options, false, response]);
11441 doFormUpload : function(o, ps, url){
11443 var frame = document.createElement('iframe');
11446 frame.className = 'x-hidden';
11448 frame.src = Roo.SSL_SECURE_URL;
11450 document.body.appendChild(frame);
11453 document.frames[id].name = id;
11456 var form = Roo.getDom(o.form);
11458 form.method = 'POST';
11459 form.enctype = form.encoding = 'multipart/form-data';
11465 if(ps){ // add dynamic params
11467 ps = Roo.urlDecode(ps, false);
11469 if(ps.hasOwnProperty(k)){
11470 hd = document.createElement('input');
11471 hd.type = 'hidden';
11474 form.appendChild(hd);
11481 var r = { // bogus response object
11486 r.argument = o ? o.argument : null;
11491 doc = frame.contentWindow.document;
11493 doc = (frame.contentDocument || window.frames[id].document);
11495 if(doc && doc.body){
11496 r.responseText = doc.body.innerHTML;
11498 if(doc && doc.XMLDocument){
11499 r.responseXML = doc.XMLDocument;
11501 r.responseXML = doc;
11508 Roo.EventManager.removeListener(frame, 'load', cb, this);
11510 this.fireEvent("requestcomplete", this, r, o);
11511 Roo.callback(o.success, o.scope, [r, o]);
11512 Roo.callback(o.callback, o.scope, [o, true, r]);
11514 setTimeout(function(){document.body.removeChild(frame);}, 100);
11517 Roo.EventManager.on(frame, 'load', cb, this);
11520 if(hiddens){ // remove dynamic params
11521 for(var i = 0, len = hiddens.length; i < len; i++){
11522 form.removeChild(hiddens[i]);
11530 * @extends Roo.data.Connection
11531 * Global Ajax request class.
11535 Roo.Ajax = new Roo.data.Connection({
11538 * @cfg {String} url @hide
11541 * @cfg {Object} extraParams @hide
11544 * @cfg {Object} defaultHeaders @hide
11547 * @cfg {String} method (Optional) @hide
11550 * @cfg {Number} timeout (Optional) @hide
11553 * @cfg {Boolean} autoAbort (Optional) @hide
11557 * @cfg {Boolean} disableCaching (Optional) @hide
11561 * @property disableCaching
11562 * True to add a unique cache-buster param to GET requests. (defaults to true)
11567 * The default URL to be used for requests to the server. (defaults to undefined)
11571 * @property extraParams
11572 * An object containing properties which are used as
11573 * extra parameters to each request made by this object. (defaults to undefined)
11577 * @property defaultHeaders
11578 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11583 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11587 * @property timeout
11588 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11593 * @property autoAbort
11594 * Whether a new request should abort any pending requests. (defaults to false)
11600 * Serialize the passed form into a url encoded string
11601 * @param {String/HTMLElement} form
11604 serializeForm : function(form){
11605 return Roo.lib.Ajax.serializeForm(form);
11609 * Ext JS Library 1.1.1
11610 * Copyright(c) 2006-2007, Ext JS, LLC.
11612 * Originally Released Under LGPL - original licence link has changed is not relivant.
11615 * <script type="text/javascript">
11619 * Global Ajax request class.
11622 * @extends Roo.data.Connection
11625 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11626 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11627 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11628 * @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)
11629 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11630 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11631 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11633 Roo.Ajax = new Roo.data.Connection({
11642 * Serialize the passed form into a url encoded string
11644 * @param {String/HTMLElement} form
11647 serializeForm : function(form){
11648 return Roo.lib.Ajax.serializeForm(form);
11652 * Ext JS Library 1.1.1
11653 * Copyright(c) 2006-2007, Ext JS, LLC.
11655 * Originally Released Under LGPL - original licence link has changed is not relivant.
11658 * <script type="text/javascript">
11663 * @class Roo.UpdateManager
11664 * @extends Roo.util.Observable
11665 * Provides AJAX-style update for Element object.<br><br>
11668 * // Get it from a Roo.Element object
11669 * var el = Roo.get("foo");
11670 * var mgr = el.getUpdateManager();
11671 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11673 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11675 * // or directly (returns the same UpdateManager instance)
11676 * var mgr = new Roo.UpdateManager("myElementId");
11677 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11678 * mgr.on("update", myFcnNeedsToKnow);
11680 // short handed call directly from the element object
11681 Roo.get("foo").load({
11685 text: "Loading Foo..."
11689 * Create new UpdateManager directly.
11690 * @param {String/HTMLElement/Roo.Element} el The element to update
11691 * @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).
11693 Roo.UpdateManager = function(el, forceNew){
11695 if(!forceNew && el.updateManager){
11696 return el.updateManager;
11699 * The Element object
11700 * @type Roo.Element
11704 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11707 this.defaultUrl = null;
11711 * @event beforeupdate
11712 * Fired before an update is made, return false from your handler and the update is cancelled.
11713 * @param {Roo.Element} el
11714 * @param {String/Object/Function} url
11715 * @param {String/Object} params
11717 "beforeupdate": true,
11720 * Fired after successful update is made.
11721 * @param {Roo.Element} el
11722 * @param {Object} oResponseObject The response Object
11727 * Fired on update failure.
11728 * @param {Roo.Element} el
11729 * @param {Object} oResponseObject The response Object
11733 var d = Roo.UpdateManager.defaults;
11735 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11738 this.sslBlankUrl = d.sslBlankUrl;
11740 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11743 this.disableCaching = d.disableCaching;
11745 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11748 this.indicatorText = d.indicatorText;
11750 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11753 this.showLoadIndicator = d.showLoadIndicator;
11755 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11758 this.timeout = d.timeout;
11761 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11764 this.loadScripts = d.loadScripts;
11767 * Transaction object of current executing transaction
11769 this.transaction = null;
11774 this.autoRefreshProcId = null;
11776 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11779 this.refreshDelegate = this.refresh.createDelegate(this);
11781 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11784 this.updateDelegate = this.update.createDelegate(this);
11786 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11789 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11793 this.successDelegate = this.processSuccess.createDelegate(this);
11797 this.failureDelegate = this.processFailure.createDelegate(this);
11799 if(!this.renderer){
11801 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11803 this.renderer = new Roo.UpdateManager.BasicRenderer();
11806 Roo.UpdateManager.superclass.constructor.call(this);
11809 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11811 * Get the Element this UpdateManager is bound to
11812 * @return {Roo.Element} The element
11814 getEl : function(){
11818 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11819 * @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:
11822 url: "your-url.php",<br/>
11823 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11824 callback: yourFunction,<br/>
11825 scope: yourObject, //(optional scope) <br/>
11826 discardUrl: false, <br/>
11827 nocache: false,<br/>
11828 text: "Loading...",<br/>
11830 scripts: false<br/>
11833 * The only required property is url. The optional properties nocache, text and scripts
11834 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11835 * @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}
11836 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11837 * @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.
11839 update : function(url, params, callback, discardUrl){
11840 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11841 var method = this.method, cfg;
11842 if(typeof url == "object"){ // must be config object
11845 params = params || cfg.params;
11846 callback = callback || cfg.callback;
11847 discardUrl = discardUrl || cfg.discardUrl;
11848 if(callback && cfg.scope){
11849 callback = callback.createDelegate(cfg.scope);
11851 if(typeof cfg.method != "undefined"){method = cfg.method;};
11852 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11853 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11854 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11855 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11857 this.showLoading();
11859 this.defaultUrl = url;
11861 if(typeof url == "function"){
11862 url = url.call(this);
11865 method = method || (params ? "POST" : "GET");
11866 if(method == "GET"){
11867 url = this.prepareUrl(url);
11870 var o = Roo.apply(cfg ||{}, {
11873 success: this.successDelegate,
11874 failure: this.failureDelegate,
11875 callback: undefined,
11876 timeout: (this.timeout*1000),
11877 argument: {"url": url, "form": null, "callback": callback, "params": params}
11880 this.transaction = Roo.Ajax.request(o);
11885 * 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.
11886 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11887 * @param {String/HTMLElement} form The form Id or form element
11888 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11889 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11890 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11892 formUpdate : function(form, url, reset, callback){
11893 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11894 if(typeof url == "function"){
11895 url = url.call(this);
11897 form = Roo.getDom(form);
11898 this.transaction = Roo.Ajax.request({
11901 success: this.successDelegate,
11902 failure: this.failureDelegate,
11903 timeout: (this.timeout*1000),
11904 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11906 this.showLoading.defer(1, this);
11911 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11912 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11914 refresh : function(callback){
11915 if(this.defaultUrl == null){
11918 this.update(this.defaultUrl, null, callback, true);
11922 * Set this element to auto refresh.
11923 * @param {Number} interval How often to update (in seconds).
11924 * @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)
11925 * @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}
11926 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11927 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11929 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11931 this.update(url || this.defaultUrl, params, callback, true);
11933 if(this.autoRefreshProcId){
11934 clearInterval(this.autoRefreshProcId);
11936 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11940 * Stop auto refresh on this element.
11942 stopAutoRefresh : function(){
11943 if(this.autoRefreshProcId){
11944 clearInterval(this.autoRefreshProcId);
11945 delete this.autoRefreshProcId;
11949 isAutoRefreshing : function(){
11950 return this.autoRefreshProcId ? true : false;
11953 * Called to update the element to "Loading" state. Override to perform custom action.
11955 showLoading : function(){
11956 if(this.showLoadIndicator){
11957 this.el.update(this.indicatorText);
11962 * Adds unique parameter to query string if disableCaching = true
11965 prepareUrl : function(url){
11966 if(this.disableCaching){
11967 var append = "_dc=" + (new Date().getTime());
11968 if(url.indexOf("?") !== -1){
11969 url += "&" + append;
11971 url += "?" + append;
11980 processSuccess : function(response){
11981 this.transaction = null;
11982 if(response.argument.form && response.argument.reset){
11983 try{ // put in try/catch since some older FF releases had problems with this
11984 response.argument.form.reset();
11987 if(this.loadScripts){
11988 this.renderer.render(this.el, response, this,
11989 this.updateComplete.createDelegate(this, [response]));
11991 this.renderer.render(this.el, response, this);
11992 this.updateComplete(response);
11996 updateComplete : function(response){
11997 this.fireEvent("update", this.el, response);
11998 if(typeof response.argument.callback == "function"){
11999 response.argument.callback(this.el, true, response);
12006 processFailure : function(response){
12007 this.transaction = null;
12008 this.fireEvent("failure", this.el, response);
12009 if(typeof response.argument.callback == "function"){
12010 response.argument.callback(this.el, false, response);
12015 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12016 * @param {Object} renderer The object implementing the render() method
12018 setRenderer : function(renderer){
12019 this.renderer = renderer;
12022 getRenderer : function(){
12023 return this.renderer;
12027 * Set the defaultUrl used for updates
12028 * @param {String/Function} defaultUrl The url or a function to call to get the url
12030 setDefaultUrl : function(defaultUrl){
12031 this.defaultUrl = defaultUrl;
12035 * Aborts the executing transaction
12037 abort : function(){
12038 if(this.transaction){
12039 Roo.Ajax.abort(this.transaction);
12044 * Returns true if an update is in progress
12045 * @return {Boolean}
12047 isUpdating : function(){
12048 if(this.transaction){
12049 return Roo.Ajax.isLoading(this.transaction);
12056 * @class Roo.UpdateManager.defaults
12057 * @static (not really - but it helps the doc tool)
12058 * The defaults collection enables customizing the default properties of UpdateManager
12060 Roo.UpdateManager.defaults = {
12062 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12068 * True to process scripts by default (Defaults to false).
12071 loadScripts : false,
12074 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12077 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12079 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12082 disableCaching : false,
12084 * Whether to show indicatorText when loading (Defaults to true).
12087 showLoadIndicator : true,
12089 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12092 indicatorText : '<div class="loading-indicator">Loading...</div>'
12096 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12098 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12099 * @param {String/HTMLElement/Roo.Element} el The element to update
12100 * @param {String} url The url
12101 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12102 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12105 * @member Roo.UpdateManager
12107 Roo.UpdateManager.updateElement = function(el, url, params, options){
12108 var um = Roo.get(el, true).getUpdateManager();
12109 Roo.apply(um, options);
12110 um.update(url, params, options ? options.callback : null);
12112 // alias for backwards compat
12113 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12115 * @class Roo.UpdateManager.BasicRenderer
12116 * Default Content renderer. Updates the elements innerHTML with the responseText.
12118 Roo.UpdateManager.BasicRenderer = function(){};
12120 Roo.UpdateManager.BasicRenderer.prototype = {
12122 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12123 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12124 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12125 * @param {Roo.Element} el The element being rendered
12126 * @param {Object} response The YUI Connect response object
12127 * @param {UpdateManager} updateManager The calling update manager
12128 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12130 render : function(el, response, updateManager, callback){
12131 el.update(response.responseText, updateManager.loadScripts, callback);
12136 * Ext JS Library 1.1.1
12137 * Copyright(c) 2006-2007, Ext JS, LLC.
12139 * Originally Released Under LGPL - original licence link has changed is not relivant.
12142 * <script type="text/javascript">
12146 * @class Roo.util.DelayedTask
12147 * Provides a convenient method of performing setTimeout where a new
12148 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12149 * You can use this class to buffer
12150 * the keypress events for a certain number of milliseconds, and perform only if they stop
12151 * for that amount of time.
12152 * @constructor The parameters to this constructor serve as defaults and are not required.
12153 * @param {Function} fn (optional) The default function to timeout
12154 * @param {Object} scope (optional) The default scope of that timeout
12155 * @param {Array} args (optional) The default Array of arguments
12157 Roo.util.DelayedTask = function(fn, scope, args){
12158 var id = null, d, t;
12160 var call = function(){
12161 var now = new Date().getTime();
12165 fn.apply(scope, args || []);
12169 * Cancels any pending timeout and queues a new one
12170 * @param {Number} delay The milliseconds to delay
12171 * @param {Function} newFn (optional) Overrides function passed to constructor
12172 * @param {Object} newScope (optional) Overrides scope passed to constructor
12173 * @param {Array} newArgs (optional) Overrides args passed to constructor
12175 this.delay = function(delay, newFn, newScope, newArgs){
12176 if(id && delay != d){
12180 t = new Date().getTime();
12182 scope = newScope || scope;
12183 args = newArgs || args;
12185 id = setInterval(call, d);
12190 * Cancel the last queued timeout
12192 this.cancel = function(){
12200 * Ext JS Library 1.1.1
12201 * Copyright(c) 2006-2007, Ext JS, LLC.
12203 * Originally Released Under LGPL - original licence link has changed is not relivant.
12206 * <script type="text/javascript">
12210 Roo.util.TaskRunner = function(interval){
12211 interval = interval || 10;
12212 var tasks = [], removeQueue = [];
12214 var running = false;
12216 var stopThread = function(){
12222 var startThread = function(){
12225 id = setInterval(runTasks, interval);
12229 var removeTask = function(task){
12230 removeQueue.push(task);
12236 var runTasks = function(){
12237 if(removeQueue.length > 0){
12238 for(var i = 0, len = removeQueue.length; i < len; i++){
12239 tasks.remove(removeQueue[i]);
12242 if(tasks.length < 1){
12247 var now = new Date().getTime();
12248 for(var i = 0, len = tasks.length; i < len; ++i){
12250 var itime = now - t.taskRunTime;
12251 if(t.interval <= itime){
12252 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12253 t.taskRunTime = now;
12254 if(rt === false || t.taskRunCount === t.repeat){
12259 if(t.duration && t.duration <= (now - t.taskStartTime)){
12266 * Queues a new task.
12267 * @param {Object} task
12269 this.start = function(task){
12271 task.taskStartTime = new Date().getTime();
12272 task.taskRunTime = 0;
12273 task.taskRunCount = 0;
12278 this.stop = function(task){
12283 this.stopAll = function(){
12285 for(var i = 0, len = tasks.length; i < len; i++){
12286 if(tasks[i].onStop){
12295 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12297 * Ext JS Library 1.1.1
12298 * Copyright(c) 2006-2007, Ext JS, LLC.
12300 * Originally Released Under LGPL - original licence link has changed is not relivant.
12303 * <script type="text/javascript">
12308 * @class Roo.util.MixedCollection
12309 * @extends Roo.util.Observable
12310 * A Collection class that maintains both numeric indexes and keys and exposes events.
12312 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12313 * collection (defaults to false)
12314 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12315 * and return the key value for that item. This is used when available to look up the key on items that
12316 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12317 * equivalent to providing an implementation for the {@link #getKey} method.
12319 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12327 * Fires when the collection is cleared.
12332 * Fires when an item is added to the collection.
12333 * @param {Number} index The index at which the item was added.
12334 * @param {Object} o The item added.
12335 * @param {String} key The key associated with the added item.
12340 * Fires when an item is replaced in the collection.
12341 * @param {String} key he key associated with the new added.
12342 * @param {Object} old The item being replaced.
12343 * @param {Object} new The new item.
12348 * Fires when an item is removed from the collection.
12349 * @param {Object} o The item being removed.
12350 * @param {String} key (optional) The key associated with the removed item.
12355 this.allowFunctions = allowFunctions === true;
12357 this.getKey = keyFn;
12359 Roo.util.MixedCollection.superclass.constructor.call(this);
12362 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12363 allowFunctions : false,
12366 * Adds an item to the collection.
12367 * @param {String} key The key to associate with the item
12368 * @param {Object} o The item to add.
12369 * @return {Object} The item added.
12371 add : function(key, o){
12372 if(arguments.length == 1){
12374 key = this.getKey(o);
12376 if(typeof key == "undefined" || key === null){
12378 this.items.push(o);
12379 this.keys.push(null);
12381 var old = this.map[key];
12383 return this.replace(key, o);
12386 this.items.push(o);
12388 this.keys.push(key);
12390 this.fireEvent("add", this.length-1, o, key);
12395 * MixedCollection has a generic way to fetch keys if you implement getKey.
12398 var mc = new Roo.util.MixedCollection();
12399 mc.add(someEl.dom.id, someEl);
12400 mc.add(otherEl.dom.id, otherEl);
12404 var mc = new Roo.util.MixedCollection();
12405 mc.getKey = function(el){
12411 // or via the constructor
12412 var mc = new Roo.util.MixedCollection(false, function(el){
12418 * @param o {Object} The item for which to find the key.
12419 * @return {Object} The key for the passed item.
12421 getKey : function(o){
12426 * Replaces an item in the collection.
12427 * @param {String} key The key associated with the item to replace, or the item to replace.
12428 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12429 * @return {Object} The new item.
12431 replace : function(key, o){
12432 if(arguments.length == 1){
12434 key = this.getKey(o);
12436 var old = this.item(key);
12437 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12438 return this.add(key, o);
12440 var index = this.indexOfKey(key);
12441 this.items[index] = o;
12443 this.fireEvent("replace", key, old, o);
12448 * Adds all elements of an Array or an Object to the collection.
12449 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12450 * an Array of values, each of which are added to the collection.
12452 addAll : function(objs){
12453 if(arguments.length > 1 || objs instanceof Array){
12454 var args = arguments.length > 1 ? arguments : objs;
12455 for(var i = 0, len = args.length; i < len; i++){
12459 for(var key in objs){
12460 if(this.allowFunctions || typeof objs[key] != "function"){
12461 this.add(key, objs[key]);
12468 * Executes the specified function once for every item in the collection, passing each
12469 * item as the first and only parameter. returning false from the function will stop the iteration.
12470 * @param {Function} fn The function to execute for each item.
12471 * @param {Object} scope (optional) The scope in which to execute the function.
12473 each : function(fn, scope){
12474 var items = [].concat(this.items); // each safe for removal
12475 for(var i = 0, len = items.length; i < len; i++){
12476 if(fn.call(scope || items[i], items[i], i, len) === false){
12483 * Executes the specified function once for every key in the collection, passing each
12484 * key, and its associated item as the first two parameters.
12485 * @param {Function} fn The function to execute for each item.
12486 * @param {Object} scope (optional) The scope in which to execute the function.
12488 eachKey : function(fn, scope){
12489 for(var i = 0, len = this.keys.length; i < len; i++){
12490 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12495 * Returns the first item in the collection which elicits a true return value from the
12496 * passed selection function.
12497 * @param {Function} fn The selection function to execute for each item.
12498 * @param {Object} scope (optional) The scope in which to execute the function.
12499 * @return {Object} The first item in the collection which returned true from the selection function.
12501 find : function(fn, scope){
12502 for(var i = 0, len = this.items.length; i < len; i++){
12503 if(fn.call(scope || window, this.items[i], this.keys[i])){
12504 return this.items[i];
12511 * Inserts an item at the specified index in the collection.
12512 * @param {Number} index The index to insert the item at.
12513 * @param {String} key The key to associate with the new item, or the item itself.
12514 * @param {Object} o (optional) If the second parameter was a key, the new item.
12515 * @return {Object} The item inserted.
12517 insert : function(index, key, o){
12518 if(arguments.length == 2){
12520 key = this.getKey(o);
12522 if(index >= this.length){
12523 return this.add(key, o);
12526 this.items.splice(index, 0, o);
12527 if(typeof key != "undefined" && key != null){
12530 this.keys.splice(index, 0, key);
12531 this.fireEvent("add", index, o, key);
12536 * Removed an item from the collection.
12537 * @param {Object} o The item to remove.
12538 * @return {Object} The item removed.
12540 remove : function(o){
12541 return this.removeAt(this.indexOf(o));
12545 * Remove an item from a specified index in the collection.
12546 * @param {Number} index The index within the collection of the item to remove.
12548 removeAt : function(index){
12549 if(index < this.length && index >= 0){
12551 var o = this.items[index];
12552 this.items.splice(index, 1);
12553 var key = this.keys[index];
12554 if(typeof key != "undefined"){
12555 delete this.map[key];
12557 this.keys.splice(index, 1);
12558 this.fireEvent("remove", o, key);
12563 * Removed an item associated with the passed key fom the collection.
12564 * @param {String} key The key of the item to remove.
12566 removeKey : function(key){
12567 return this.removeAt(this.indexOfKey(key));
12571 * Returns the number of items in the collection.
12572 * @return {Number} the number of items in the collection.
12574 getCount : function(){
12575 return this.length;
12579 * Returns index within the collection of the passed Object.
12580 * @param {Object} o The item to find the index of.
12581 * @return {Number} index of the item.
12583 indexOf : function(o){
12584 if(!this.items.indexOf){
12585 for(var i = 0, len = this.items.length; i < len; i++){
12586 if(this.items[i] == o) return i;
12590 return this.items.indexOf(o);
12595 * Returns index within the collection of the passed key.
12596 * @param {String} key The key to find the index of.
12597 * @return {Number} index of the key.
12599 indexOfKey : function(key){
12600 if(!this.keys.indexOf){
12601 for(var i = 0, len = this.keys.length; i < len; i++){
12602 if(this.keys[i] == key) return i;
12606 return this.keys.indexOf(key);
12611 * Returns the item associated with the passed key OR index. Key has priority over index.
12612 * @param {String/Number} key The key or index of the item.
12613 * @return {Object} The item associated with the passed key.
12615 item : function(key){
12616 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12617 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12621 * Returns the item at the specified index.
12622 * @param {Number} index The index of the item.
12625 itemAt : function(index){
12626 return this.items[index];
12630 * Returns the item associated with the passed key.
12631 * @param {String/Number} key The key of the item.
12632 * @return {Object} The item associated with the passed key.
12634 key : function(key){
12635 return this.map[key];
12639 * Returns true if the collection contains the passed Object as an item.
12640 * @param {Object} o The Object to look for in the collection.
12641 * @return {Boolean} True if the collection contains the Object as an item.
12643 contains : function(o){
12644 return this.indexOf(o) != -1;
12648 * Returns true if the collection contains the passed Object as a key.
12649 * @param {String} key The key to look for in the collection.
12650 * @return {Boolean} True if the collection contains the Object as a key.
12652 containsKey : function(key){
12653 return typeof this.map[key] != "undefined";
12657 * Removes all items from the collection.
12659 clear : function(){
12664 this.fireEvent("clear");
12668 * Returns the first item in the collection.
12669 * @return {Object} the first item in the collection..
12671 first : function(){
12672 return this.items[0];
12676 * Returns the last item in the collection.
12677 * @return {Object} the last item in the collection..
12680 return this.items[this.length-1];
12683 _sort : function(property, dir, fn){
12684 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12685 fn = fn || function(a, b){
12688 var c = [], k = this.keys, items = this.items;
12689 for(var i = 0, len = items.length; i < len; i++){
12690 c[c.length] = {key: k[i], value: items[i], index: i};
12692 c.sort(function(a, b){
12693 var v = fn(a[property], b[property]) * dsc;
12695 v = (a.index < b.index ? -1 : 1);
12699 for(var i = 0, len = c.length; i < len; i++){
12700 items[i] = c[i].value;
12703 this.fireEvent("sort", this);
12707 * Sorts this collection with the passed comparison function
12708 * @param {String} direction (optional) "ASC" or "DESC"
12709 * @param {Function} fn (optional) comparison function
12711 sort : function(dir, fn){
12712 this._sort("value", dir, fn);
12716 * Sorts this collection by keys
12717 * @param {String} direction (optional) "ASC" or "DESC"
12718 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12720 keySort : function(dir, fn){
12721 this._sort("key", dir, fn || function(a, b){
12722 return String(a).toUpperCase()-String(b).toUpperCase();
12727 * Returns a range of items in this collection
12728 * @param {Number} startIndex (optional) defaults to 0
12729 * @param {Number} endIndex (optional) default to the last item
12730 * @return {Array} An array of items
12732 getRange : function(start, end){
12733 var items = this.items;
12734 if(items.length < 1){
12737 start = start || 0;
12738 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12741 for(var i = start; i <= end; i++) {
12742 r[r.length] = items[i];
12745 for(var i = start; i >= end; i--) {
12746 r[r.length] = items[i];
12753 * Filter the <i>objects</i> in this collection by a specific property.
12754 * Returns a new collection that has been filtered.
12755 * @param {String} property A property on your objects
12756 * @param {String/RegExp} value Either string that the property values
12757 * should start with or a RegExp to test against the property
12758 * @return {MixedCollection} The new filtered collection
12760 filter : function(property, value){
12761 if(!value.exec){ // not a regex
12762 value = String(value);
12763 if(value.length == 0){
12764 return this.clone();
12766 value = new RegExp("^" + Roo.escapeRe(value), "i");
12768 return this.filterBy(function(o){
12769 return o && value.test(o[property]);
12774 * Filter by a function. * Returns a new collection that has been filtered.
12775 * The passed function will be called with each
12776 * object in the collection. If the function returns true, the value is included
12777 * otherwise it is filtered.
12778 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12779 * @param {Object} scope (optional) The scope of the function (defaults to this)
12780 * @return {MixedCollection} The new filtered collection
12782 filterBy : function(fn, scope){
12783 var r = new Roo.util.MixedCollection();
12784 r.getKey = this.getKey;
12785 var k = this.keys, it = this.items;
12786 for(var i = 0, len = it.length; i < len; i++){
12787 if(fn.call(scope||this, it[i], k[i])){
12788 r.add(k[i], it[i]);
12795 * Creates a duplicate of this collection
12796 * @return {MixedCollection}
12798 clone : function(){
12799 var r = new Roo.util.MixedCollection();
12800 var k = this.keys, it = this.items;
12801 for(var i = 0, len = it.length; i < len; i++){
12802 r.add(k[i], it[i]);
12804 r.getKey = this.getKey;
12809 * Returns the item associated with the passed key or index.
12811 * @param {String/Number} key The key or index of the item.
12812 * @return {Object} The item associated with the passed key.
12814 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12816 * Ext JS Library 1.1.1
12817 * Copyright(c) 2006-2007, Ext JS, LLC.
12819 * Originally Released Under LGPL - original licence link has changed is not relivant.
12822 * <script type="text/javascript">
12825 * @class Roo.util.JSON
12826 * Modified version of Douglas Crockford"s json.js that doesn"t
12827 * mess with the Object prototype
12828 * http://www.json.org/js.html
12831 Roo.util.JSON = new (function(){
12832 var useHasOwn = {}.hasOwnProperty ? true : false;
12834 // crashes Safari in some instances
12835 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12837 var pad = function(n) {
12838 return n < 10 ? "0" + n : n;
12851 var encodeString = function(s){
12852 if (/["\\\x00-\x1f]/.test(s)) {
12853 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12858 c = b.charCodeAt();
12860 Math.floor(c / 16).toString(16) +
12861 (c % 16).toString(16);
12864 return '"' + s + '"';
12867 var encodeArray = function(o){
12868 var a = ["["], b, i, l = o.length, v;
12869 for (i = 0; i < l; i += 1) {
12871 switch (typeof v) {
12880 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12888 var encodeDate = function(o){
12889 return '"' + o.getFullYear() + "-" +
12890 pad(o.getMonth() + 1) + "-" +
12891 pad(o.getDate()) + "T" +
12892 pad(o.getHours()) + ":" +
12893 pad(o.getMinutes()) + ":" +
12894 pad(o.getSeconds()) + '"';
12898 * Encodes an Object, Array or other value
12899 * @param {Mixed} o The variable to encode
12900 * @return {String} The JSON string
12902 this.encode = function(o)
12904 // should this be extended to fully wrap stringify..
12906 if(typeof o == "undefined" || o === null){
12908 }else if(o instanceof Array){
12909 return encodeArray(o);
12910 }else if(o instanceof Date){
12911 return encodeDate(o);
12912 }else if(typeof o == "string"){
12913 return encodeString(o);
12914 }else if(typeof o == "number"){
12915 return isFinite(o) ? String(o) : "null";
12916 }else if(typeof o == "boolean"){
12919 var a = ["{"], b, i, v;
12921 if(!useHasOwn || o.hasOwnProperty(i)) {
12923 switch (typeof v) {
12932 a.push(this.encode(i), ":",
12933 v === null ? "null" : this.encode(v));
12944 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12945 * @param {String} json The JSON string
12946 * @return {Object} The resulting object
12948 this.decode = function(json){
12950 return /** eval:var:json */ eval("(" + json + ')');
12954 * Shorthand for {@link Roo.util.JSON#encode}
12955 * @member Roo encode
12957 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12959 * Shorthand for {@link Roo.util.JSON#decode}
12960 * @member Roo decode
12962 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12965 * Ext JS Library 1.1.1
12966 * Copyright(c) 2006-2007, Ext JS, LLC.
12968 * Originally Released Under LGPL - original licence link has changed is not relivant.
12971 * <script type="text/javascript">
12975 * @class Roo.util.Format
12976 * Reusable data formatting functions
12979 Roo.util.Format = function(){
12980 var trimRe = /^\s+|\s+$/g;
12983 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12984 * @param {String} value The string to truncate
12985 * @param {Number} length The maximum length to allow before truncating
12986 * @return {String} The converted text
12988 ellipsis : function(value, len){
12989 if(value && value.length > len){
12990 return value.substr(0, len-3)+"...";
12996 * Checks a reference and converts it to empty string if it is undefined
12997 * @param {Mixed} value Reference to check
12998 * @return {Mixed} Empty string if converted, otherwise the original value
13000 undef : function(value){
13001 return typeof value != "undefined" ? value : "";
13005 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13006 * @param {String} value The string to encode
13007 * @return {String} The encoded text
13009 htmlEncode : function(value){
13010 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13014 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13015 * @param {String} value The string to decode
13016 * @return {String} The decoded text
13018 htmlDecode : function(value){
13019 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13023 * Trims any whitespace from either side of a string
13024 * @param {String} value The text to trim
13025 * @return {String} The trimmed text
13027 trim : function(value){
13028 return String(value).replace(trimRe, "");
13032 * Returns a substring from within an original string
13033 * @param {String} value The original text
13034 * @param {Number} start The start index of the substring
13035 * @param {Number} length The length of the substring
13036 * @return {String} The substring
13038 substr : function(value, start, length){
13039 return String(value).substr(start, length);
13043 * Converts a string to all lower case letters
13044 * @param {String} value The text to convert
13045 * @return {String} The converted text
13047 lowercase : function(value){
13048 return String(value).toLowerCase();
13052 * Converts a string to all upper case letters
13053 * @param {String} value The text to convert
13054 * @return {String} The converted text
13056 uppercase : function(value){
13057 return String(value).toUpperCase();
13061 * Converts the first character only of a string to upper case
13062 * @param {String} value The text to convert
13063 * @return {String} The converted text
13065 capitalize : function(value){
13066 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13070 call : function(value, fn){
13071 if(arguments.length > 2){
13072 var args = Array.prototype.slice.call(arguments, 2);
13073 args.unshift(value);
13075 return /** eval:var:value */ eval(fn).apply(window, args);
13077 /** eval:var:value */
13078 return /** eval:var:value */ eval(fn).call(window, value);
13084 * safer version of Math.toFixed..??/
13085 * @param {Number/String} value The numeric value to format
13086 * @param {Number/String} value Decimal places
13087 * @return {String} The formatted currency string
13089 toFixed : function(v, n)
13091 // why not use to fixed - precision is buggered???
13093 return Math.round(v-0);
13095 var fact = Math.pow(10,n+1);
13096 v = (Math.round((v-0)*fact))/fact;
13097 var z = (''+fact).substring(2);
13098 if (v == Math.floor(v)) {
13099 return Math.floor(v) + '.' + z;
13102 // now just padd decimals..
13103 var ps = String(v).split('.');
13104 var fd = (ps[1] + z);
13105 var r = fd.substring(0,n);
13106 var rm = fd.substring(n);
13108 return ps[0] + '.' + r;
13110 r*=1; // turn it into a number;
13112 if (String(r).length != n) {
13115 r = String(r).substring(1); // chop the end off.
13118 return ps[0] + '.' + r;
13123 * Format a number as US currency
13124 * @param {Number/String} value The numeric value to format
13125 * @return {String} The formatted currency string
13127 usMoney : function(v){
13128 v = (Math.round((v-0)*100))/100;
13129 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13131 var ps = v.split('.');
13133 var sub = ps[1] ? '.'+ ps[1] : '.00';
13134 var r = /(\d+)(\d{3})/;
13135 while (r.test(whole)) {
13136 whole = whole.replace(r, '$1' + ',' + '$2');
13138 return "$" + whole + sub ;
13142 * Parse a value into a formatted date using the specified format pattern.
13143 * @param {Mixed} value The value to format
13144 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13145 * @return {String} The formatted date string
13147 date : function(v, format){
13151 if(!(v instanceof Date)){
13152 v = new Date(Date.parse(v));
13154 return v.dateFormat(format || "m/d/Y");
13158 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13159 * @param {String} format Any valid date format string
13160 * @return {Function} The date formatting function
13162 dateRenderer : function(format){
13163 return function(v){
13164 return Roo.util.Format.date(v, format);
13169 stripTagsRE : /<\/?[^>]+>/gi,
13172 * Strips all HTML tags
13173 * @param {Mixed} value The text from which to strip tags
13174 * @return {String} The stripped text
13176 stripTags : function(v){
13177 return !v ? v : String(v).replace(this.stripTagsRE, "");
13182 * Ext JS Library 1.1.1
13183 * Copyright(c) 2006-2007, Ext JS, LLC.
13185 * Originally Released Under LGPL - original licence link has changed is not relivant.
13188 * <script type="text/javascript">
13195 * @class Roo.MasterTemplate
13196 * @extends Roo.Template
13197 * Provides a template that can have child templates. The syntax is:
13199 var t = new Roo.MasterTemplate(
13200 '<select name="{name}">',
13201 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13204 t.add('options', {value: 'foo', text: 'bar'});
13205 // or you can add multiple child elements in one shot
13206 t.addAll('options', [
13207 {value: 'foo', text: 'bar'},
13208 {value: 'foo2', text: 'bar2'},
13209 {value: 'foo3', text: 'bar3'}
13211 // then append, applying the master template values
13212 t.append('my-form', {name: 'my-select'});
13214 * A name attribute for the child template is not required if you have only one child
13215 * template or you want to refer to them by index.
13217 Roo.MasterTemplate = function(){
13218 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13219 this.originalHtml = this.html;
13221 var m, re = this.subTemplateRe;
13224 while(m = re.exec(this.html)){
13225 var name = m[1], content = m[2];
13230 tpl : new Roo.Template(content)
13233 st[name] = st[subIndex];
13235 st[subIndex].tpl.compile();
13236 st[subIndex].tpl.call = this.call.createDelegate(this);
13239 this.subCount = subIndex;
13242 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13244 * The regular expression used to match sub templates
13248 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13251 * Applies the passed values to a child template.
13252 * @param {String/Number} name (optional) The name or index of the child template
13253 * @param {Array/Object} values The values to be applied to the template
13254 * @return {MasterTemplate} this
13256 add : function(name, values){
13257 if(arguments.length == 1){
13258 values = arguments[0];
13261 var s = this.subs[name];
13262 s.buffer[s.buffer.length] = s.tpl.apply(values);
13267 * Applies all the passed values to a child template.
13268 * @param {String/Number} name (optional) The name or index of the child template
13269 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13270 * @param {Boolean} reset (optional) True to reset the template first
13271 * @return {MasterTemplate} this
13273 fill : function(name, values, reset){
13275 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13283 for(var i = 0, len = values.length; i < len; i++){
13284 this.add(name, values[i]);
13290 * Resets the template for reuse
13291 * @return {MasterTemplate} this
13293 reset : function(){
13295 for(var i = 0; i < this.subCount; i++){
13301 applyTemplate : function(values){
13303 var replaceIndex = -1;
13304 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13305 return s[++replaceIndex].buffer.join("");
13307 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13310 apply : function(){
13311 return this.applyTemplate.apply(this, arguments);
13314 compile : function(){return this;}
13318 * Alias for fill().
13321 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13323 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13324 * var tpl = Roo.MasterTemplate.from('element-id');
13325 * @param {String/HTMLElement} el
13326 * @param {Object} config
13329 Roo.MasterTemplate.from = function(el, config){
13330 el = Roo.getDom(el);
13331 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13334 * Ext JS Library 1.1.1
13335 * Copyright(c) 2006-2007, Ext JS, LLC.
13337 * Originally Released Under LGPL - original licence link has changed is not relivant.
13340 * <script type="text/javascript">
13345 * @class Roo.util.CSS
13346 * Utility class for manipulating CSS rules
13349 Roo.util.CSS = function(){
13351 var doc = document;
13353 var camelRe = /(-[a-z])/gi;
13354 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13358 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13359 * tag and appended to the HEAD of the document.
13360 * @param {String|Object} cssText The text containing the css rules
13361 * @param {String} id An id to add to the stylesheet for later removal
13362 * @return {StyleSheet}
13364 createStyleSheet : function(cssText, id){
13366 var head = doc.getElementsByTagName("head")[0];
13367 var nrules = doc.createElement("style");
13368 nrules.setAttribute("type", "text/css");
13370 nrules.setAttribute("id", id);
13372 if (typeof(cssText) != 'string') {
13373 // support object maps..
13374 // not sure if this a good idea..
13375 // perhaps it should be merged with the general css handling
13376 // and handle js style props.
13377 var cssTextNew = [];
13378 for(var n in cssText) {
13380 for(var k in cssText[n]) {
13381 citems.push( k + ' : ' +cssText[n][k] + ';' );
13383 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13386 cssText = cssTextNew.join("\n");
13392 head.appendChild(nrules);
13393 ss = nrules.styleSheet;
13394 ss.cssText = cssText;
13397 nrules.appendChild(doc.createTextNode(cssText));
13399 nrules.cssText = cssText;
13401 head.appendChild(nrules);
13402 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13404 this.cacheStyleSheet(ss);
13409 * Removes a style or link tag by id
13410 * @param {String} id The id of the tag
13412 removeStyleSheet : function(id){
13413 var existing = doc.getElementById(id);
13415 existing.parentNode.removeChild(existing);
13420 * Dynamically swaps an existing stylesheet reference for a new one
13421 * @param {String} id The id of an existing link tag to remove
13422 * @param {String} url The href of the new stylesheet to include
13424 swapStyleSheet : function(id, url){
13425 this.removeStyleSheet(id);
13426 var ss = doc.createElement("link");
13427 ss.setAttribute("rel", "stylesheet");
13428 ss.setAttribute("type", "text/css");
13429 ss.setAttribute("id", id);
13430 ss.setAttribute("href", url);
13431 doc.getElementsByTagName("head")[0].appendChild(ss);
13435 * Refresh the rule cache if you have dynamically added stylesheets
13436 * @return {Object} An object (hash) of rules indexed by selector
13438 refreshCache : function(){
13439 return this.getRules(true);
13443 cacheStyleSheet : function(stylesheet){
13447 try{// try catch for cross domain access issue
13448 var ssRules = stylesheet.cssRules || stylesheet.rules;
13449 for(var j = ssRules.length-1; j >= 0; --j){
13450 rules[ssRules[j].selectorText] = ssRules[j];
13456 * Gets all css rules for the document
13457 * @param {Boolean} refreshCache true to refresh the internal cache
13458 * @return {Object} An object (hash) of rules indexed by selector
13460 getRules : function(refreshCache){
13461 if(rules == null || refreshCache){
13463 var ds = doc.styleSheets;
13464 for(var i =0, len = ds.length; i < len; i++){
13466 this.cacheStyleSheet(ds[i]);
13474 * Gets an an individual CSS rule by selector(s)
13475 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13476 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13477 * @return {CSSRule} The CSS rule or null if one is not found
13479 getRule : function(selector, refreshCache){
13480 var rs = this.getRules(refreshCache);
13481 if(!(selector instanceof Array)){
13482 return rs[selector];
13484 for(var i = 0; i < selector.length; i++){
13485 if(rs[selector[i]]){
13486 return rs[selector[i]];
13494 * Updates a rule property
13495 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13496 * @param {String} property The css property
13497 * @param {String} value The new value for the property
13498 * @return {Boolean} true If a rule was found and updated
13500 updateRule : function(selector, property, value){
13501 if(!(selector instanceof Array)){
13502 var rule = this.getRule(selector);
13504 rule.style[property.replace(camelRe, camelFn)] = value;
13508 for(var i = 0; i < selector.length; i++){
13509 if(this.updateRule(selector[i], property, value)){
13519 * Ext JS Library 1.1.1
13520 * Copyright(c) 2006-2007, Ext JS, LLC.
13522 * Originally Released Under LGPL - original licence link has changed is not relivant.
13525 * <script type="text/javascript">
13531 * @class Roo.util.ClickRepeater
13532 * @extends Roo.util.Observable
13534 * A wrapper class which can be applied to any element. Fires a "click" event while the
13535 * mouse is pressed. The interval between firings may be specified in the config but
13536 * defaults to 10 milliseconds.
13538 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13540 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13541 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13542 * Similar to an autorepeat key delay.
13543 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13544 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13545 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13546 * "interval" and "delay" are ignored. "immediate" is honored.
13547 * @cfg {Boolean} preventDefault True to prevent the default click event
13548 * @cfg {Boolean} stopDefault True to stop the default click event
13551 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13552 * 2007-02-02 jvs Renamed to ClickRepeater
13553 * 2007-02-03 jvs Modifications for FF Mac and Safari
13556 * @param {String/HTMLElement/Element} el The element to listen on
13557 * @param {Object} config
13559 Roo.util.ClickRepeater = function(el, config)
13561 this.el = Roo.get(el);
13562 this.el.unselectable();
13564 Roo.apply(this, config);
13569 * Fires when the mouse button is depressed.
13570 * @param {Roo.util.ClickRepeater} this
13572 "mousedown" : true,
13575 * Fires on a specified interval during the time the element is pressed.
13576 * @param {Roo.util.ClickRepeater} this
13581 * Fires when the mouse key is released.
13582 * @param {Roo.util.ClickRepeater} this
13587 this.el.on("mousedown", this.handleMouseDown, this);
13588 if(this.preventDefault || this.stopDefault){
13589 this.el.on("click", function(e){
13590 if(this.preventDefault){
13591 e.preventDefault();
13593 if(this.stopDefault){
13599 // allow inline handler
13601 this.on("click", this.handler, this.scope || this);
13604 Roo.util.ClickRepeater.superclass.constructor.call(this);
13607 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13610 preventDefault : true,
13611 stopDefault : false,
13615 handleMouseDown : function(){
13616 clearTimeout(this.timer);
13618 if(this.pressClass){
13619 this.el.addClass(this.pressClass);
13621 this.mousedownTime = new Date();
13623 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13624 this.el.on("mouseout", this.handleMouseOut, this);
13626 this.fireEvent("mousedown", this);
13627 this.fireEvent("click", this);
13629 this.timer = this.click.defer(this.delay || this.interval, this);
13633 click : function(){
13634 this.fireEvent("click", this);
13635 this.timer = this.click.defer(this.getInterval(), this);
13639 getInterval: function(){
13640 if(!this.accelerate){
13641 return this.interval;
13643 var pressTime = this.mousedownTime.getElapsed();
13644 if(pressTime < 500){
13646 }else if(pressTime < 1700){
13648 }else if(pressTime < 2600){
13650 }else if(pressTime < 3500){
13652 }else if(pressTime < 4400){
13654 }else if(pressTime < 5300){
13656 }else if(pressTime < 6200){
13664 handleMouseOut : function(){
13665 clearTimeout(this.timer);
13666 if(this.pressClass){
13667 this.el.removeClass(this.pressClass);
13669 this.el.on("mouseover", this.handleMouseReturn, this);
13673 handleMouseReturn : function(){
13674 this.el.un("mouseover", this.handleMouseReturn);
13675 if(this.pressClass){
13676 this.el.addClass(this.pressClass);
13682 handleMouseUp : function(){
13683 clearTimeout(this.timer);
13684 this.el.un("mouseover", this.handleMouseReturn);
13685 this.el.un("mouseout", this.handleMouseOut);
13686 Roo.get(document).un("mouseup", this.handleMouseUp);
13687 this.el.removeClass(this.pressClass);
13688 this.fireEvent("mouseup", this);
13692 * Ext JS Library 1.1.1
13693 * Copyright(c) 2006-2007, Ext JS, LLC.
13695 * Originally Released Under LGPL - original licence link has changed is not relivant.
13698 * <script type="text/javascript">
13703 * @class Roo.KeyNav
13704 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13705 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13706 * way to implement custom navigation schemes for any UI component.</p>
13707 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13708 * pageUp, pageDown, del, home, end. Usage:</p>
13710 var nav = new Roo.KeyNav("my-element", {
13711 "left" : function(e){
13712 this.moveLeft(e.ctrlKey);
13714 "right" : function(e){
13715 this.moveRight(e.ctrlKey);
13717 "enter" : function(e){
13724 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13725 * @param {Object} config The config
13727 Roo.KeyNav = function(el, config){
13728 this.el = Roo.get(el);
13729 Roo.apply(this, config);
13730 if(!this.disabled){
13731 this.disabled = true;
13736 Roo.KeyNav.prototype = {
13738 * @cfg {Boolean} disabled
13739 * True to disable this KeyNav instance (defaults to false)
13743 * @cfg {String} defaultEventAction
13744 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13745 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13746 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13748 defaultEventAction: "stopEvent",
13750 * @cfg {Boolean} forceKeyDown
13751 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13752 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13753 * handle keydown instead of keypress.
13755 forceKeyDown : false,
13758 prepareEvent : function(e){
13759 var k = e.getKey();
13760 var h = this.keyToHandler[k];
13761 //if(h && this[h]){
13762 // e.stopPropagation();
13764 if(Roo.isSafari && h && k >= 37 && k <= 40){
13770 relay : function(e){
13771 var k = e.getKey();
13772 var h = this.keyToHandler[k];
13774 if(this.doRelay(e, this[h], h) !== true){
13775 e[this.defaultEventAction]();
13781 doRelay : function(e, h, hname){
13782 return h.call(this.scope || this, e);
13785 // possible handlers
13799 // quick lookup hash
13816 * Enable this KeyNav
13818 enable: function(){
13820 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13821 // the EventObject will normalize Safari automatically
13822 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13823 this.el.on("keydown", this.relay, this);
13825 this.el.on("keydown", this.prepareEvent, this);
13826 this.el.on("keypress", this.relay, this);
13828 this.disabled = false;
13833 * Disable this KeyNav
13835 disable: function(){
13836 if(!this.disabled){
13837 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13838 this.el.un("keydown", this.relay);
13840 this.el.un("keydown", this.prepareEvent);
13841 this.el.un("keypress", this.relay);
13843 this.disabled = true;
13848 * Ext JS Library 1.1.1
13849 * Copyright(c) 2006-2007, Ext JS, LLC.
13851 * Originally Released Under LGPL - original licence link has changed is not relivant.
13854 * <script type="text/javascript">
13859 * @class Roo.KeyMap
13860 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13861 * The constructor accepts the same config object as defined by {@link #addBinding}.
13862 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13863 * combination it will call the function with this signature (if the match is a multi-key
13864 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13865 * A KeyMap can also handle a string representation of keys.<br />
13868 // map one key by key code
13869 var map = new Roo.KeyMap("my-element", {
13870 key: 13, // or Roo.EventObject.ENTER
13875 // map multiple keys to one action by string
13876 var map = new Roo.KeyMap("my-element", {
13882 // map multiple keys to multiple actions by strings and array of codes
13883 var map = new Roo.KeyMap("my-element", [
13886 fn: function(){ alert("Return was pressed"); }
13889 fn: function(){ alert('a, b or c was pressed'); }
13894 fn: function(){ alert('Control + shift + tab was pressed.'); }
13898 * <b>Note: A KeyMap starts enabled</b>
13900 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13901 * @param {Object} config The config (see {@link #addBinding})
13902 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13904 Roo.KeyMap = function(el, config, eventName){
13905 this.el = Roo.get(el);
13906 this.eventName = eventName || "keydown";
13907 this.bindings = [];
13909 this.addBinding(config);
13914 Roo.KeyMap.prototype = {
13916 * True to stop the event from bubbling and prevent the default browser action if the
13917 * key was handled by the KeyMap (defaults to false)
13923 * Add a new binding to this KeyMap. The following config object properties are supported:
13925 Property Type Description
13926 ---------- --------------- ----------------------------------------------------------------------
13927 key String/Array A single keycode or an array of keycodes to handle
13928 shift Boolean True to handle key only when shift is pressed (defaults to false)
13929 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13930 alt Boolean True to handle key only when alt is pressed (defaults to false)
13931 fn Function The function to call when KeyMap finds the expected key combination
13932 scope Object The scope of the callback function
13938 var map = new Roo.KeyMap(document, {
13939 key: Roo.EventObject.ENTER,
13944 //Add a new binding to the existing KeyMap later
13952 * @param {Object/Array} config A single KeyMap config or an array of configs
13954 addBinding : function(config){
13955 if(config instanceof Array){
13956 for(var i = 0, len = config.length; i < len; i++){
13957 this.addBinding(config[i]);
13961 var keyCode = config.key,
13962 shift = config.shift,
13963 ctrl = config.ctrl,
13966 scope = config.scope;
13967 if(typeof keyCode == "string"){
13969 var keyString = keyCode.toUpperCase();
13970 for(var j = 0, len = keyString.length; j < len; j++){
13971 ks.push(keyString.charCodeAt(j));
13975 var keyArray = keyCode instanceof Array;
13976 var handler = function(e){
13977 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13978 var k = e.getKey();
13980 for(var i = 0, len = keyCode.length; i < len; i++){
13981 if(keyCode[i] == k){
13982 if(this.stopEvent){
13985 fn.call(scope || window, k, e);
13991 if(this.stopEvent){
13994 fn.call(scope || window, k, e);
13999 this.bindings.push(handler);
14003 * Shorthand for adding a single key listener
14004 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14005 * following options:
14006 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14007 * @param {Function} fn The function to call
14008 * @param {Object} scope (optional) The scope of the function
14010 on : function(key, fn, scope){
14011 var keyCode, shift, ctrl, alt;
14012 if(typeof key == "object" && !(key instanceof Array)){
14031 handleKeyDown : function(e){
14032 if(this.enabled){ //just in case
14033 var b = this.bindings;
14034 for(var i = 0, len = b.length; i < len; i++){
14035 b[i].call(this, e);
14041 * Returns true if this KeyMap is enabled
14042 * @return {Boolean}
14044 isEnabled : function(){
14045 return this.enabled;
14049 * Enables this KeyMap
14051 enable: function(){
14053 this.el.on(this.eventName, this.handleKeyDown, this);
14054 this.enabled = true;
14059 * Disable this KeyMap
14061 disable: function(){
14063 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14064 this.enabled = false;
14069 * Ext JS Library 1.1.1
14070 * Copyright(c) 2006-2007, Ext JS, LLC.
14072 * Originally Released Under LGPL - original licence link has changed is not relivant.
14075 * <script type="text/javascript">
14080 * @class Roo.util.TextMetrics
14081 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14082 * wide, in pixels, a given block of text will be.
14085 Roo.util.TextMetrics = function(){
14089 * Measures the size of the specified text
14090 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14091 * that can affect the size of the rendered text
14092 * @param {String} text The text to measure
14093 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14094 * in order to accurately measure the text height
14095 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14097 measure : function(el, text, fixedWidth){
14099 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14102 shared.setFixedWidth(fixedWidth || 'auto');
14103 return shared.getSize(text);
14107 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14108 * the overhead of multiple calls to initialize the style properties on each measurement.
14109 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14110 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14111 * in order to accurately measure the text height
14112 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14114 createInstance : function(el, fixedWidth){
14115 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14122 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14123 var ml = new Roo.Element(document.createElement('div'));
14124 document.body.appendChild(ml.dom);
14125 ml.position('absolute');
14126 ml.setLeftTop(-1000, -1000);
14130 ml.setWidth(fixedWidth);
14135 * Returns the size of the specified text based on the internal element's style and width properties
14136 * @memberOf Roo.util.TextMetrics.Instance#
14137 * @param {String} text The text to measure
14138 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14140 getSize : function(text){
14142 var s = ml.getSize();
14148 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14149 * that can affect the size of the rendered text
14150 * @memberOf Roo.util.TextMetrics.Instance#
14151 * @param {String/HTMLElement} el The element, dom node or id
14153 bind : function(el){
14155 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14160 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14161 * to set a fixed width in order to accurately measure the text height.
14162 * @memberOf Roo.util.TextMetrics.Instance#
14163 * @param {Number} width The width to set on the element
14165 setFixedWidth : function(width){
14166 ml.setWidth(width);
14170 * Returns the measured width of the specified text
14171 * @memberOf Roo.util.TextMetrics.Instance#
14172 * @param {String} text The text to measure
14173 * @return {Number} width The width in pixels
14175 getWidth : function(text){
14176 ml.dom.style.width = 'auto';
14177 return this.getSize(text).width;
14181 * Returns the measured height of the specified text. For multiline text, be sure to call
14182 * {@link #setFixedWidth} if necessary.
14183 * @memberOf Roo.util.TextMetrics.Instance#
14184 * @param {String} text The text to measure
14185 * @return {Number} height The height in pixels
14187 getHeight : function(text){
14188 return this.getSize(text).height;
14192 instance.bind(bindTo);
14197 // backwards compat
14198 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14200 * Ext JS Library 1.1.1
14201 * Copyright(c) 2006-2007, Ext JS, LLC.
14203 * Originally Released Under LGPL - original licence link has changed is not relivant.
14206 * <script type="text/javascript">
14210 * @class Roo.state.Provider
14211 * Abstract base class for state provider implementations. This class provides methods
14212 * for encoding and decoding <b>typed</b> variables including dates and defines the
14213 * Provider interface.
14215 Roo.state.Provider = function(){
14217 * @event statechange
14218 * Fires when a state change occurs.
14219 * @param {Provider} this This state provider
14220 * @param {String} key The state key which was changed
14221 * @param {String} value The encoded value for the state
14224 "statechange": true
14227 Roo.state.Provider.superclass.constructor.call(this);
14229 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14231 * Returns the current value for a key
14232 * @param {String} name The key name
14233 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14234 * @return {Mixed} The state data
14236 get : function(name, defaultValue){
14237 return typeof this.state[name] == "undefined" ?
14238 defaultValue : this.state[name];
14242 * Clears a value from the state
14243 * @param {String} name The key name
14245 clear : function(name){
14246 delete this.state[name];
14247 this.fireEvent("statechange", this, name, null);
14251 * Sets the value for a key
14252 * @param {String} name The key name
14253 * @param {Mixed} value The value to set
14255 set : function(name, value){
14256 this.state[name] = value;
14257 this.fireEvent("statechange", this, name, value);
14261 * Decodes a string previously encoded with {@link #encodeValue}.
14262 * @param {String} value The value to decode
14263 * @return {Mixed} The decoded value
14265 decodeValue : function(cookie){
14266 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14267 var matches = re.exec(unescape(cookie));
14268 if(!matches || !matches[1]) return; // non state cookie
14269 var type = matches[1];
14270 var v = matches[2];
14273 return parseFloat(v);
14275 return new Date(Date.parse(v));
14280 var values = v.split("^");
14281 for(var i = 0, len = values.length; i < len; i++){
14282 all.push(this.decodeValue(values[i]));
14287 var values = v.split("^");
14288 for(var i = 0, len = values.length; i < len; i++){
14289 var kv = values[i].split("=");
14290 all[kv[0]] = this.decodeValue(kv[1]);
14299 * Encodes a value including type information. Decode with {@link #decodeValue}.
14300 * @param {Mixed} value The value to encode
14301 * @return {String} The encoded value
14303 encodeValue : function(v){
14305 if(typeof v == "number"){
14307 }else if(typeof v == "boolean"){
14308 enc = "b:" + (v ? "1" : "0");
14309 }else if(v instanceof Date){
14310 enc = "d:" + v.toGMTString();
14311 }else if(v instanceof Array){
14313 for(var i = 0, len = v.length; i < len; i++){
14314 flat += this.encodeValue(v[i]);
14315 if(i != len-1) flat += "^";
14318 }else if(typeof v == "object"){
14321 if(typeof v[key] != "function"){
14322 flat += key + "=" + this.encodeValue(v[key]) + "^";
14325 enc = "o:" + flat.substring(0, flat.length-1);
14329 return escape(enc);
14335 * Ext JS Library 1.1.1
14336 * Copyright(c) 2006-2007, Ext JS, LLC.
14338 * Originally Released Under LGPL - original licence link has changed is not relivant.
14341 * <script type="text/javascript">
14344 * @class Roo.state.Manager
14345 * This is the global state manager. By default all components that are "state aware" check this class
14346 * for state information if you don't pass them a custom state provider. In order for this class
14347 * to be useful, it must be initialized with a provider when your application initializes.
14349 // in your initialization function
14351 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14353 // supposed you have a {@link Roo.BorderLayout}
14354 var layout = new Roo.BorderLayout(...);
14355 layout.restoreState();
14356 // or a {Roo.BasicDialog}
14357 var dialog = new Roo.BasicDialog(...);
14358 dialog.restoreState();
14362 Roo.state.Manager = function(){
14363 var provider = new Roo.state.Provider();
14367 * Configures the default state provider for your application
14368 * @param {Provider} stateProvider The state provider to set
14370 setProvider : function(stateProvider){
14371 provider = stateProvider;
14375 * Returns the current value for a key
14376 * @param {String} name The key name
14377 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14378 * @return {Mixed} The state data
14380 get : function(key, defaultValue){
14381 return provider.get(key, defaultValue);
14385 * Sets the value for a key
14386 * @param {String} name The key name
14387 * @param {Mixed} value The state data
14389 set : function(key, value){
14390 provider.set(key, value);
14394 * Clears a value from the state
14395 * @param {String} name The key name
14397 clear : function(key){
14398 provider.clear(key);
14402 * Gets the currently configured state provider
14403 * @return {Provider} The state provider
14405 getProvider : function(){
14412 * Ext JS Library 1.1.1
14413 * Copyright(c) 2006-2007, Ext JS, LLC.
14415 * Originally Released Under LGPL - original licence link has changed is not relivant.
14418 * <script type="text/javascript">
14421 * @class Roo.state.CookieProvider
14422 * @extends Roo.state.Provider
14423 * The default Provider implementation which saves state via cookies.
14426 var cp = new Roo.state.CookieProvider({
14428 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14429 domain: "roojs.com"
14431 Roo.state.Manager.setProvider(cp);
14433 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14434 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14435 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14436 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14437 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14438 * domain the page is running on including the 'www' like 'www.roojs.com')
14439 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14441 * Create a new CookieProvider
14442 * @param {Object} config The configuration object
14444 Roo.state.CookieProvider = function(config){
14445 Roo.state.CookieProvider.superclass.constructor.call(this);
14447 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14448 this.domain = null;
14449 this.secure = false;
14450 Roo.apply(this, config);
14451 this.state = this.readCookies();
14454 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14456 set : function(name, value){
14457 if(typeof value == "undefined" || value === null){
14461 this.setCookie(name, value);
14462 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14466 clear : function(name){
14467 this.clearCookie(name);
14468 Roo.state.CookieProvider.superclass.clear.call(this, name);
14472 readCookies : function(){
14474 var c = document.cookie + ";";
14475 var re = /\s?(.*?)=(.*?);/g;
14477 while((matches = re.exec(c)) != null){
14478 var name = matches[1];
14479 var value = matches[2];
14480 if(name && name.substring(0,3) == "ys-"){
14481 cookies[name.substr(3)] = this.decodeValue(value);
14488 setCookie : function(name, value){
14489 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14490 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14491 ((this.path == null) ? "" : ("; path=" + this.path)) +
14492 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14493 ((this.secure == true) ? "; secure" : "");
14497 clearCookie : function(name){
14498 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14499 ((this.path == null) ? "" : ("; path=" + this.path)) +
14500 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14501 ((this.secure == true) ? "; secure" : "");
14505 * Ext JS Library 1.1.1
14506 * Copyright(c) 2006-2007, Ext JS, LLC.
14508 * Originally Released Under LGPL - original licence link has changed is not relivant.
14511 * <script type="text/javascript">
14517 * These classes are derivatives of the similarly named classes in the YUI Library.
14518 * The original license:
14519 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14520 * Code licensed under the BSD License:
14521 * http://developer.yahoo.net/yui/license.txt
14526 var Event=Roo.EventManager;
14527 var Dom=Roo.lib.Dom;
14530 * @class Roo.dd.DragDrop
14531 * @extends Roo.util.Observable
14532 * Defines the interface and base operation of items that that can be
14533 * dragged or can be drop targets. It was designed to be extended, overriding
14534 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14535 * Up to three html elements can be associated with a DragDrop instance:
14537 * <li>linked element: the element that is passed into the constructor.
14538 * This is the element which defines the boundaries for interaction with
14539 * other DragDrop objects.</li>
14540 * <li>handle element(s): The drag operation only occurs if the element that
14541 * was clicked matches a handle element. By default this is the linked
14542 * element, but there are times that you will want only a portion of the
14543 * linked element to initiate the drag operation, and the setHandleElId()
14544 * method provides a way to define this.</li>
14545 * <li>drag element: this represents the element that would be moved along
14546 * with the cursor during a drag operation. By default, this is the linked
14547 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14548 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14551 * This class should not be instantiated until the onload event to ensure that
14552 * the associated elements are available.
14553 * The following would define a DragDrop obj that would interact with any
14554 * other DragDrop obj in the "group1" group:
14556 * dd = new Roo.dd.DragDrop("div1", "group1");
14558 * Since none of the event handlers have been implemented, nothing would
14559 * actually happen if you were to run the code above. Normally you would
14560 * override this class or one of the default implementations, but you can
14561 * also override the methods you want on an instance of the class...
14563 * dd.onDragDrop = function(e, id) {
14564 * alert("dd was dropped on " + id);
14568 * @param {String} id of the element that is linked to this instance
14569 * @param {String} sGroup the group of related DragDrop objects
14570 * @param {object} config an object containing configurable attributes
14571 * Valid properties for DragDrop:
14572 * padding, isTarget, maintainOffset, primaryButtonOnly
14574 Roo.dd.DragDrop = function(id, sGroup, config) {
14576 this.init(id, sGroup, config);
14581 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14584 * The id of the element associated with this object. This is what we
14585 * refer to as the "linked element" because the size and position of
14586 * this element is used to determine when the drag and drop objects have
14594 * Configuration attributes passed into the constructor
14601 * The id of the element that will be dragged. By default this is same
14602 * as the linked element , but could be changed to another element. Ex:
14604 * @property dragElId
14611 * the id of the element that initiates the drag operation. By default
14612 * this is the linked element, but could be changed to be a child of this
14613 * element. This lets us do things like only starting the drag when the
14614 * header element within the linked html element is clicked.
14615 * @property handleElId
14622 * An associative array of HTML tags that will be ignored if clicked.
14623 * @property invalidHandleTypes
14624 * @type {string: string}
14626 invalidHandleTypes: null,
14629 * An associative array of ids for elements that will be ignored if clicked
14630 * @property invalidHandleIds
14631 * @type {string: string}
14633 invalidHandleIds: null,
14636 * An indexted array of css class names for elements that will be ignored
14638 * @property invalidHandleClasses
14641 invalidHandleClasses: null,
14644 * The linked element's absolute X position at the time the drag was
14646 * @property startPageX
14653 * The linked element's absolute X position at the time the drag was
14655 * @property startPageY
14662 * The group defines a logical collection of DragDrop objects that are
14663 * related. Instances only get events when interacting with other
14664 * DragDrop object in the same group. This lets us define multiple
14665 * groups using a single DragDrop subclass if we want.
14667 * @type {string: string}
14672 * Individual drag/drop instances can be locked. This will prevent
14673 * onmousedown start drag.
14681 * Lock this instance
14684 lock: function() { this.locked = true; },
14687 * Unlock this instace
14690 unlock: function() { this.locked = false; },
14693 * By default, all insances can be a drop target. This can be disabled by
14694 * setting isTarget to false.
14701 * The padding configured for this drag and drop object for calculating
14702 * the drop zone intersection with this object.
14709 * Cached reference to the linked element
14710 * @property _domRef
14716 * Internal typeof flag
14717 * @property __ygDragDrop
14720 __ygDragDrop: true,
14723 * Set to true when horizontal contraints are applied
14724 * @property constrainX
14731 * Set to true when vertical contraints are applied
14732 * @property constrainY
14739 * The left constraint
14747 * The right constraint
14755 * The up constraint
14764 * The down constraint
14772 * Maintain offsets when we resetconstraints. Set to true when you want
14773 * the position of the element relative to its parent to stay the same
14774 * when the page changes
14776 * @property maintainOffset
14779 maintainOffset: false,
14782 * Array of pixel locations the element will snap to if we specified a
14783 * horizontal graduation/interval. This array is generated automatically
14784 * when you define a tick interval.
14791 * Array of pixel locations the element will snap to if we specified a
14792 * vertical graduation/interval. This array is generated automatically
14793 * when you define a tick interval.
14800 * By default the drag and drop instance will only respond to the primary
14801 * button click (left button for a right-handed mouse). Set to true to
14802 * allow drag and drop to start with any mouse click that is propogated
14804 * @property primaryButtonOnly
14807 primaryButtonOnly: true,
14810 * The availabe property is false until the linked dom element is accessible.
14811 * @property available
14817 * By default, drags can only be initiated if the mousedown occurs in the
14818 * region the linked element is. This is done in part to work around a
14819 * bug in some browsers that mis-report the mousedown if the previous
14820 * mouseup happened outside of the window. This property is set to true
14821 * if outer handles are defined.
14823 * @property hasOuterHandles
14827 hasOuterHandles: false,
14830 * Code that executes immediately before the startDrag event
14831 * @method b4StartDrag
14834 b4StartDrag: function(x, y) { },
14837 * Abstract method called after a drag/drop object is clicked
14838 * and the drag or mousedown time thresholds have beeen met.
14839 * @method startDrag
14840 * @param {int} X click location
14841 * @param {int} Y click location
14843 startDrag: function(x, y) { /* override this */ },
14846 * Code that executes immediately before the onDrag event
14850 b4Drag: function(e) { },
14853 * Abstract method called during the onMouseMove event while dragging an
14856 * @param {Event} e the mousemove event
14858 onDrag: function(e) { /* override this */ },
14861 * Abstract method called when this element fist begins hovering over
14862 * another DragDrop obj
14863 * @method onDragEnter
14864 * @param {Event} e the mousemove event
14865 * @param {String|DragDrop[]} id In POINT mode, the element
14866 * id this is hovering over. In INTERSECT mode, an array of one or more
14867 * dragdrop items being hovered over.
14869 onDragEnter: function(e, id) { /* override this */ },
14872 * Code that executes immediately before the onDragOver event
14873 * @method b4DragOver
14876 b4DragOver: function(e) { },
14879 * Abstract method called when this element is hovering over another
14881 * @method onDragOver
14882 * @param {Event} e the mousemove event
14883 * @param {String|DragDrop[]} id In POINT mode, the element
14884 * id this is hovering over. In INTERSECT mode, an array of dd items
14885 * being hovered over.
14887 onDragOver: function(e, id) { /* override this */ },
14890 * Code that executes immediately before the onDragOut event
14891 * @method b4DragOut
14894 b4DragOut: function(e) { },
14897 * Abstract method called when we are no longer hovering over an element
14898 * @method onDragOut
14899 * @param {Event} e the mousemove event
14900 * @param {String|DragDrop[]} id In POINT mode, the element
14901 * id this was hovering over. In INTERSECT mode, an array of dd items
14902 * that the mouse is no longer over.
14904 onDragOut: function(e, id) { /* override this */ },
14907 * Code that executes immediately before the onDragDrop event
14908 * @method b4DragDrop
14911 b4DragDrop: function(e) { },
14914 * Abstract method called when this item is dropped on another DragDrop
14916 * @method onDragDrop
14917 * @param {Event} e the mouseup event
14918 * @param {String|DragDrop[]} id In POINT mode, the element
14919 * id this was dropped on. In INTERSECT mode, an array of dd items this
14922 onDragDrop: function(e, id) { /* override this */ },
14925 * Abstract method called when this item is dropped on an area with no
14927 * @method onInvalidDrop
14928 * @param {Event} e the mouseup event
14930 onInvalidDrop: function(e) { /* override this */ },
14933 * Code that executes immediately before the endDrag event
14934 * @method b4EndDrag
14937 b4EndDrag: function(e) { },
14940 * Fired when we are done dragging the object
14942 * @param {Event} e the mouseup event
14944 endDrag: function(e) { /* override this */ },
14947 * Code executed immediately before the onMouseDown event
14948 * @method b4MouseDown
14949 * @param {Event} e the mousedown event
14952 b4MouseDown: function(e) { },
14955 * Event handler that fires when a drag/drop obj gets a mousedown
14956 * @method onMouseDown
14957 * @param {Event} e the mousedown event
14959 onMouseDown: function(e) { /* override this */ },
14962 * Event handler that fires when a drag/drop obj gets a mouseup
14963 * @method onMouseUp
14964 * @param {Event} e the mouseup event
14966 onMouseUp: function(e) { /* override this */ },
14969 * Override the onAvailable method to do what is needed after the initial
14970 * position was determined.
14971 * @method onAvailable
14973 onAvailable: function () {
14977 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14980 defaultPadding : {left:0, right:0, top:0, bottom:0},
14983 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14987 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14988 { dragElId: "existingProxyDiv" });
14989 dd.startDrag = function(){
14990 this.constrainTo("parent-id");
14993 * Or you can initalize it using the {@link Roo.Element} object:
14995 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14996 startDrag : function(){
14997 this.constrainTo("parent-id");
15001 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15002 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15003 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15004 * an object containing the sides to pad. For example: {right:10, bottom:10}
15005 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15007 constrainTo : function(constrainTo, pad, inContent){
15008 if(typeof pad == "number"){
15009 pad = {left: pad, right:pad, top:pad, bottom:pad};
15011 pad = pad || this.defaultPadding;
15012 var b = Roo.get(this.getEl()).getBox();
15013 var ce = Roo.get(constrainTo);
15014 var s = ce.getScroll();
15015 var c, cd = ce.dom;
15016 if(cd == document.body){
15017 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15020 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15024 var topSpace = b.y - c.y;
15025 var leftSpace = b.x - c.x;
15027 this.resetConstraints();
15028 this.setXConstraint(leftSpace - (pad.left||0), // left
15029 c.width - leftSpace - b.width - (pad.right||0) //right
15031 this.setYConstraint(topSpace - (pad.top||0), //top
15032 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15037 * Returns a reference to the linked element
15039 * @return {HTMLElement} the html element
15041 getEl: function() {
15042 if (!this._domRef) {
15043 this._domRef = Roo.getDom(this.id);
15046 return this._domRef;
15050 * Returns a reference to the actual element to drag. By default this is
15051 * the same as the html element, but it can be assigned to another
15052 * element. An example of this can be found in Roo.dd.DDProxy
15053 * @method getDragEl
15054 * @return {HTMLElement} the html element
15056 getDragEl: function() {
15057 return Roo.getDom(this.dragElId);
15061 * Sets up the DragDrop object. Must be called in the constructor of any
15062 * Roo.dd.DragDrop subclass
15064 * @param id the id of the linked element
15065 * @param {String} sGroup the group of related items
15066 * @param {object} config configuration attributes
15068 init: function(id, sGroup, config) {
15069 this.initTarget(id, sGroup, config);
15070 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15071 // Event.on(this.id, "selectstart", Event.preventDefault);
15075 * Initializes Targeting functionality only... the object does not
15076 * get a mousedown handler.
15077 * @method initTarget
15078 * @param id the id of the linked element
15079 * @param {String} sGroup the group of related items
15080 * @param {object} config configuration attributes
15082 initTarget: function(id, sGroup, config) {
15084 // configuration attributes
15085 this.config = config || {};
15087 // create a local reference to the drag and drop manager
15088 this.DDM = Roo.dd.DDM;
15089 // initialize the groups array
15092 // assume that we have an element reference instead of an id if the
15093 // parameter is not a string
15094 if (typeof id !== "string") {
15101 // add to an interaction group
15102 this.addToGroup((sGroup) ? sGroup : "default");
15104 // We don't want to register this as the handle with the manager
15105 // so we just set the id rather than calling the setter.
15106 this.handleElId = id;
15108 // the linked element is the element that gets dragged by default
15109 this.setDragElId(id);
15111 // by default, clicked anchors will not start drag operations.
15112 this.invalidHandleTypes = { A: "A" };
15113 this.invalidHandleIds = {};
15114 this.invalidHandleClasses = [];
15116 this.applyConfig();
15118 this.handleOnAvailable();
15122 * Applies the configuration parameters that were passed into the constructor.
15123 * This is supposed to happen at each level through the inheritance chain. So
15124 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15125 * DragDrop in order to get all of the parameters that are available in
15127 * @method applyConfig
15129 applyConfig: function() {
15131 // configurable properties:
15132 // padding, isTarget, maintainOffset, primaryButtonOnly
15133 this.padding = this.config.padding || [0, 0, 0, 0];
15134 this.isTarget = (this.config.isTarget !== false);
15135 this.maintainOffset = (this.config.maintainOffset);
15136 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15141 * Executed when the linked element is available
15142 * @method handleOnAvailable
15145 handleOnAvailable: function() {
15146 this.available = true;
15147 this.resetConstraints();
15148 this.onAvailable();
15152 * Configures the padding for the target zone in px. Effectively expands
15153 * (or reduces) the virtual object size for targeting calculations.
15154 * Supports css-style shorthand; if only one parameter is passed, all sides
15155 * will have that padding, and if only two are passed, the top and bottom
15156 * will have the first param, the left and right the second.
15157 * @method setPadding
15158 * @param {int} iTop Top pad
15159 * @param {int} iRight Right pad
15160 * @param {int} iBot Bot pad
15161 * @param {int} iLeft Left pad
15163 setPadding: function(iTop, iRight, iBot, iLeft) {
15164 // this.padding = [iLeft, iRight, iTop, iBot];
15165 if (!iRight && 0 !== iRight) {
15166 this.padding = [iTop, iTop, iTop, iTop];
15167 } else if (!iBot && 0 !== iBot) {
15168 this.padding = [iTop, iRight, iTop, iRight];
15170 this.padding = [iTop, iRight, iBot, iLeft];
15175 * Stores the initial placement of the linked element.
15176 * @method setInitialPosition
15177 * @param {int} diffX the X offset, default 0
15178 * @param {int} diffY the Y offset, default 0
15180 setInitPosition: function(diffX, diffY) {
15181 var el = this.getEl();
15183 if (!this.DDM.verifyEl(el)) {
15187 var dx = diffX || 0;
15188 var dy = diffY || 0;
15190 var p = Dom.getXY( el );
15192 this.initPageX = p[0] - dx;
15193 this.initPageY = p[1] - dy;
15195 this.lastPageX = p[0];
15196 this.lastPageY = p[1];
15199 this.setStartPosition(p);
15203 * Sets the start position of the element. This is set when the obj
15204 * is initialized, the reset when a drag is started.
15205 * @method setStartPosition
15206 * @param pos current position (from previous lookup)
15209 setStartPosition: function(pos) {
15210 var p = pos || Dom.getXY( this.getEl() );
15211 this.deltaSetXY = null;
15213 this.startPageX = p[0];
15214 this.startPageY = p[1];
15218 * Add this instance to a group of related drag/drop objects. All
15219 * instances belong to at least one group, and can belong to as many
15220 * groups as needed.
15221 * @method addToGroup
15222 * @param sGroup {string} the name of the group
15224 addToGroup: function(sGroup) {
15225 this.groups[sGroup] = true;
15226 this.DDM.regDragDrop(this, sGroup);
15230 * Remove's this instance from the supplied interaction group
15231 * @method removeFromGroup
15232 * @param {string} sGroup The group to drop
15234 removeFromGroup: function(sGroup) {
15235 if (this.groups[sGroup]) {
15236 delete this.groups[sGroup];
15239 this.DDM.removeDDFromGroup(this, sGroup);
15243 * Allows you to specify that an element other than the linked element
15244 * will be moved with the cursor during a drag
15245 * @method setDragElId
15246 * @param id {string} the id of the element that will be used to initiate the drag
15248 setDragElId: function(id) {
15249 this.dragElId = id;
15253 * Allows you to specify a child of the linked element that should be
15254 * used to initiate the drag operation. An example of this would be if
15255 * you have a content div with text and links. Clicking anywhere in the
15256 * content area would normally start the drag operation. Use this method
15257 * to specify that an element inside of the content div is the element
15258 * that starts the drag operation.
15259 * @method setHandleElId
15260 * @param id {string} the id of the element that will be used to
15261 * initiate the drag.
15263 setHandleElId: function(id) {
15264 if (typeof id !== "string") {
15267 this.handleElId = id;
15268 this.DDM.regHandle(this.id, id);
15272 * Allows you to set an element outside of the linked element as a drag
15274 * @method setOuterHandleElId
15275 * @param id the id of the element that will be used to initiate the drag
15277 setOuterHandleElId: function(id) {
15278 if (typeof id !== "string") {
15281 Event.on(id, "mousedown",
15282 this.handleMouseDown, this);
15283 this.setHandleElId(id);
15285 this.hasOuterHandles = true;
15289 * Remove all drag and drop hooks for this element
15292 unreg: function() {
15293 Event.un(this.id, "mousedown",
15294 this.handleMouseDown);
15295 this._domRef = null;
15296 this.DDM._remove(this);
15299 destroy : function(){
15304 * Returns true if this instance is locked, or the drag drop mgr is locked
15305 * (meaning that all drag/drop is disabled on the page.)
15307 * @return {boolean} true if this obj or all drag/drop is locked, else
15310 isLocked: function() {
15311 return (this.DDM.isLocked() || this.locked);
15315 * Fired when this object is clicked
15316 * @method handleMouseDown
15318 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15321 handleMouseDown: function(e, oDD){
15322 if (this.primaryButtonOnly && e.button != 0) {
15326 if (this.isLocked()) {
15330 this.DDM.refreshCache(this.groups);
15332 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15333 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15335 if (this.clickValidator(e)) {
15337 // set the initial element position
15338 this.setStartPosition();
15341 this.b4MouseDown(e);
15342 this.onMouseDown(e);
15344 this.DDM.handleMouseDown(e, this);
15346 this.DDM.stopEvent(e);
15354 clickValidator: function(e) {
15355 var target = e.getTarget();
15356 return ( this.isValidHandleChild(target) &&
15357 (this.id == this.handleElId ||
15358 this.DDM.handleWasClicked(target, this.id)) );
15362 * Allows you to specify a tag name that should not start a drag operation
15363 * when clicked. This is designed to facilitate embedding links within a
15364 * drag handle that do something other than start the drag.
15365 * @method addInvalidHandleType
15366 * @param {string} tagName the type of element to exclude
15368 addInvalidHandleType: function(tagName) {
15369 var type = tagName.toUpperCase();
15370 this.invalidHandleTypes[type] = type;
15374 * Lets you to specify an element id for a child of a drag handle
15375 * that should not initiate a drag
15376 * @method addInvalidHandleId
15377 * @param {string} id the element id of the element you wish to ignore
15379 addInvalidHandleId: function(id) {
15380 if (typeof id !== "string") {
15383 this.invalidHandleIds[id] = id;
15387 * Lets you specify a css class of elements that will not initiate a drag
15388 * @method addInvalidHandleClass
15389 * @param {string} cssClass the class of the elements you wish to ignore
15391 addInvalidHandleClass: function(cssClass) {
15392 this.invalidHandleClasses.push(cssClass);
15396 * Unsets an excluded tag name set by addInvalidHandleType
15397 * @method removeInvalidHandleType
15398 * @param {string} tagName the type of element to unexclude
15400 removeInvalidHandleType: function(tagName) {
15401 var type = tagName.toUpperCase();
15402 // this.invalidHandleTypes[type] = null;
15403 delete this.invalidHandleTypes[type];
15407 * Unsets an invalid handle id
15408 * @method removeInvalidHandleId
15409 * @param {string} id the id of the element to re-enable
15411 removeInvalidHandleId: function(id) {
15412 if (typeof id !== "string") {
15415 delete this.invalidHandleIds[id];
15419 * Unsets an invalid css class
15420 * @method removeInvalidHandleClass
15421 * @param {string} cssClass the class of the element(s) you wish to
15424 removeInvalidHandleClass: function(cssClass) {
15425 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15426 if (this.invalidHandleClasses[i] == cssClass) {
15427 delete this.invalidHandleClasses[i];
15433 * Checks the tag exclusion list to see if this click should be ignored
15434 * @method isValidHandleChild
15435 * @param {HTMLElement} node the HTMLElement to evaluate
15436 * @return {boolean} true if this is a valid tag type, false if not
15438 isValidHandleChild: function(node) {
15441 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15444 nodeName = node.nodeName.toUpperCase();
15446 nodeName = node.nodeName;
15448 valid = valid && !this.invalidHandleTypes[nodeName];
15449 valid = valid && !this.invalidHandleIds[node.id];
15451 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15452 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15461 * Create the array of horizontal tick marks if an interval was specified
15462 * in setXConstraint().
15463 * @method setXTicks
15466 setXTicks: function(iStartX, iTickSize) {
15468 this.xTickSize = iTickSize;
15472 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15474 this.xTicks[this.xTicks.length] = i;
15479 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15481 this.xTicks[this.xTicks.length] = i;
15486 this.xTicks.sort(this.DDM.numericSort) ;
15490 * Create the array of vertical tick marks if an interval was specified in
15491 * setYConstraint().
15492 * @method setYTicks
15495 setYTicks: function(iStartY, iTickSize) {
15497 this.yTickSize = iTickSize;
15501 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15503 this.yTicks[this.yTicks.length] = i;
15508 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15510 this.yTicks[this.yTicks.length] = i;
15515 this.yTicks.sort(this.DDM.numericSort) ;
15519 * By default, the element can be dragged any place on the screen. Use
15520 * this method to limit the horizontal travel of the element. Pass in
15521 * 0,0 for the parameters if you want to lock the drag to the y axis.
15522 * @method setXConstraint
15523 * @param {int} iLeft the number of pixels the element can move to the left
15524 * @param {int} iRight the number of pixels the element can move to the
15526 * @param {int} iTickSize optional parameter for specifying that the
15528 * should move iTickSize pixels at a time.
15530 setXConstraint: function(iLeft, iRight, iTickSize) {
15531 this.leftConstraint = iLeft;
15532 this.rightConstraint = iRight;
15534 this.minX = this.initPageX - iLeft;
15535 this.maxX = this.initPageX + iRight;
15536 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15538 this.constrainX = true;
15542 * Clears any constraints applied to this instance. Also clears ticks
15543 * since they can't exist independent of a constraint at this time.
15544 * @method clearConstraints
15546 clearConstraints: function() {
15547 this.constrainX = false;
15548 this.constrainY = false;
15553 * Clears any tick interval defined for this instance
15554 * @method clearTicks
15556 clearTicks: function() {
15557 this.xTicks = null;
15558 this.yTicks = null;
15559 this.xTickSize = 0;
15560 this.yTickSize = 0;
15564 * By default, the element can be dragged any place on the screen. Set
15565 * this to limit the vertical travel of the element. Pass in 0,0 for the
15566 * parameters if you want to lock the drag to the x axis.
15567 * @method setYConstraint
15568 * @param {int} iUp the number of pixels the element can move up
15569 * @param {int} iDown the number of pixels the element can move down
15570 * @param {int} iTickSize optional parameter for specifying that the
15571 * element should move iTickSize pixels at a time.
15573 setYConstraint: function(iUp, iDown, iTickSize) {
15574 this.topConstraint = iUp;
15575 this.bottomConstraint = iDown;
15577 this.minY = this.initPageY - iUp;
15578 this.maxY = this.initPageY + iDown;
15579 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15581 this.constrainY = true;
15586 * resetConstraints must be called if you manually reposition a dd element.
15587 * @method resetConstraints
15588 * @param {boolean} maintainOffset
15590 resetConstraints: function() {
15593 // Maintain offsets if necessary
15594 if (this.initPageX || this.initPageX === 0) {
15595 // figure out how much this thing has moved
15596 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15597 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15599 this.setInitPosition(dx, dy);
15601 // This is the first time we have detected the element's position
15603 this.setInitPosition();
15606 if (this.constrainX) {
15607 this.setXConstraint( this.leftConstraint,
15608 this.rightConstraint,
15612 if (this.constrainY) {
15613 this.setYConstraint( this.topConstraint,
15614 this.bottomConstraint,
15620 * Normally the drag element is moved pixel by pixel, but we can specify
15621 * that it move a number of pixels at a time. This method resolves the
15622 * location when we have it set up like this.
15624 * @param {int} val where we want to place the object
15625 * @param {int[]} tickArray sorted array of valid points
15626 * @return {int} the closest tick
15629 getTick: function(val, tickArray) {
15632 // If tick interval is not defined, it is effectively 1 pixel,
15633 // so we return the value passed to us.
15635 } else if (tickArray[0] >= val) {
15636 // The value is lower than the first tick, so we return the first
15638 return tickArray[0];
15640 for (var i=0, len=tickArray.length; i<len; ++i) {
15642 if (tickArray[next] && tickArray[next] >= val) {
15643 var diff1 = val - tickArray[i];
15644 var diff2 = tickArray[next] - val;
15645 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15649 // The value is larger than the last tick, so we return the last
15651 return tickArray[tickArray.length - 1];
15658 * @return {string} string representation of the dd obj
15660 toString: function() {
15661 return ("DragDrop " + this.id);
15669 * Ext JS Library 1.1.1
15670 * Copyright(c) 2006-2007, Ext JS, LLC.
15672 * Originally Released Under LGPL - original licence link has changed is not relivant.
15675 * <script type="text/javascript">
15680 * The drag and drop utility provides a framework for building drag and drop
15681 * applications. In addition to enabling drag and drop for specific elements,
15682 * the drag and drop elements are tracked by the manager class, and the
15683 * interactions between the various elements are tracked during the drag and
15684 * the implementing code is notified about these important moments.
15687 // Only load the library once. Rewriting the manager class would orphan
15688 // existing drag and drop instances.
15689 if (!Roo.dd.DragDropMgr) {
15692 * @class Roo.dd.DragDropMgr
15693 * DragDropMgr is a singleton that tracks the element interaction for
15694 * all DragDrop items in the window. Generally, you will not call
15695 * this class directly, but it does have helper methods that could
15696 * be useful in your DragDrop implementations.
15699 Roo.dd.DragDropMgr = function() {
15701 var Event = Roo.EventManager;
15706 * Two dimensional Array of registered DragDrop objects. The first
15707 * dimension is the DragDrop item group, the second the DragDrop
15710 * @type {string: string}
15717 * Array of element ids defined as drag handles. Used to determine
15718 * if the element that generated the mousedown event is actually the
15719 * handle and not the html element itself.
15720 * @property handleIds
15721 * @type {string: string}
15728 * the DragDrop object that is currently being dragged
15729 * @property dragCurrent
15737 * the DragDrop object(s) that are being hovered over
15738 * @property dragOvers
15746 * the X distance between the cursor and the object being dragged
15755 * the Y distance between the cursor and the object being dragged
15764 * Flag to determine if we should prevent the default behavior of the
15765 * events we define. By default this is true, but this can be set to
15766 * false if you need the default behavior (not recommended)
15767 * @property preventDefault
15771 preventDefault: true,
15774 * Flag to determine if we should stop the propagation of the events
15775 * we generate. This is true by default but you may want to set it to
15776 * false if the html element contains other features that require the
15778 * @property stopPropagation
15782 stopPropagation: true,
15785 * Internal flag that is set to true when drag and drop has been
15787 * @property initialized
15794 * All drag and drop can be disabled.
15802 * Called the first time an element is registered.
15808 this.initialized = true;
15812 * In point mode, drag and drop interaction is defined by the
15813 * location of the cursor during the drag/drop
15821 * In intersect mode, drag and drop interactio nis defined by the
15822 * overlap of two or more drag and drop objects.
15823 * @property INTERSECT
15830 * The current drag and drop mode. Default: POINT
15838 * Runs method on all drag and drop objects
15839 * @method _execOnAll
15843 _execOnAll: function(sMethod, args) {
15844 for (var i in this.ids) {
15845 for (var j in this.ids[i]) {
15846 var oDD = this.ids[i][j];
15847 if (! this.isTypeOfDD(oDD)) {
15850 oDD[sMethod].apply(oDD, args);
15856 * Drag and drop initialization. Sets up the global event handlers
15861 _onLoad: function() {
15866 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15867 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15868 Event.on(window, "unload", this._onUnload, this, true);
15869 Event.on(window, "resize", this._onResize, this, true);
15870 // Event.on(window, "mouseout", this._test);
15875 * Reset constraints on all drag and drop objs
15876 * @method _onResize
15880 _onResize: function(e) {
15881 this._execOnAll("resetConstraints", []);
15885 * Lock all drag and drop functionality
15889 lock: function() { this.locked = true; },
15892 * Unlock all drag and drop functionality
15896 unlock: function() { this.locked = false; },
15899 * Is drag and drop locked?
15901 * @return {boolean} True if drag and drop is locked, false otherwise.
15904 isLocked: function() { return this.locked; },
15907 * Location cache that is set for all drag drop objects when a drag is
15908 * initiated, cleared when the drag is finished.
15909 * @property locationCache
15916 * Set useCache to false if you want to force object the lookup of each
15917 * drag and drop linked element constantly during a drag.
15918 * @property useCache
15925 * The number of pixels that the mouse needs to move after the
15926 * mousedown before the drag is initiated. Default=3;
15927 * @property clickPixelThresh
15931 clickPixelThresh: 3,
15934 * The number of milliseconds after the mousedown event to initiate the
15935 * drag if we don't get a mouseup event. Default=1000
15936 * @property clickTimeThresh
15940 clickTimeThresh: 350,
15943 * Flag that indicates that either the drag pixel threshold or the
15944 * mousdown time threshold has been met
15945 * @property dragThreshMet
15950 dragThreshMet: false,
15953 * Timeout used for the click time threshold
15954 * @property clickTimeout
15959 clickTimeout: null,
15962 * The X position of the mousedown event stored for later use when a
15963 * drag threshold is met.
15972 * The Y position of the mousedown event stored for later use when a
15973 * drag threshold is met.
15982 * Each DragDrop instance must be registered with the DragDropMgr.
15983 * This is executed in DragDrop.init()
15984 * @method regDragDrop
15985 * @param {DragDrop} oDD the DragDrop object to register
15986 * @param {String} sGroup the name of the group this element belongs to
15989 regDragDrop: function(oDD, sGroup) {
15990 if (!this.initialized) { this.init(); }
15992 if (!this.ids[sGroup]) {
15993 this.ids[sGroup] = {};
15995 this.ids[sGroup][oDD.id] = oDD;
15999 * Removes the supplied dd instance from the supplied group. Executed
16000 * by DragDrop.removeFromGroup, so don't call this function directly.
16001 * @method removeDDFromGroup
16005 removeDDFromGroup: function(oDD, sGroup) {
16006 if (!this.ids[sGroup]) {
16007 this.ids[sGroup] = {};
16010 var obj = this.ids[sGroup];
16011 if (obj && obj[oDD.id]) {
16012 delete obj[oDD.id];
16017 * Unregisters a drag and drop item. This is executed in
16018 * DragDrop.unreg, use that method instead of calling this directly.
16023 _remove: function(oDD) {
16024 for (var g in oDD.groups) {
16025 if (g && this.ids[g][oDD.id]) {
16026 delete this.ids[g][oDD.id];
16029 delete this.handleIds[oDD.id];
16033 * Each DragDrop handle element must be registered. This is done
16034 * automatically when executing DragDrop.setHandleElId()
16035 * @method regHandle
16036 * @param {String} sDDId the DragDrop id this element is a handle for
16037 * @param {String} sHandleId the id of the element that is the drag
16041 regHandle: function(sDDId, sHandleId) {
16042 if (!this.handleIds[sDDId]) {
16043 this.handleIds[sDDId] = {};
16045 this.handleIds[sDDId][sHandleId] = sHandleId;
16049 * Utility function to determine if a given element has been
16050 * registered as a drag drop item.
16051 * @method isDragDrop
16052 * @param {String} id the element id to check
16053 * @return {boolean} true if this element is a DragDrop item,
16057 isDragDrop: function(id) {
16058 return ( this.getDDById(id) ) ? true : false;
16062 * Returns the drag and drop instances that are in all groups the
16063 * passed in instance belongs to.
16064 * @method getRelated
16065 * @param {DragDrop} p_oDD the obj to get related data for
16066 * @param {boolean} bTargetsOnly if true, only return targetable objs
16067 * @return {DragDrop[]} the related instances
16070 getRelated: function(p_oDD, bTargetsOnly) {
16072 for (var i in p_oDD.groups) {
16073 for (j in this.ids[i]) {
16074 var dd = this.ids[i][j];
16075 if (! this.isTypeOfDD(dd)) {
16078 if (!bTargetsOnly || dd.isTarget) {
16079 oDDs[oDDs.length] = dd;
16088 * Returns true if the specified dd target is a legal target for
16089 * the specifice drag obj
16090 * @method isLegalTarget
16091 * @param {DragDrop} the drag obj
16092 * @param {DragDrop} the target
16093 * @return {boolean} true if the target is a legal target for the
16097 isLegalTarget: function (oDD, oTargetDD) {
16098 var targets = this.getRelated(oDD, true);
16099 for (var i=0, len=targets.length;i<len;++i) {
16100 if (targets[i].id == oTargetDD.id) {
16109 * My goal is to be able to transparently determine if an object is
16110 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16111 * returns "object", oDD.constructor.toString() always returns
16112 * "DragDrop" and not the name of the subclass. So for now it just
16113 * evaluates a well-known variable in DragDrop.
16114 * @method isTypeOfDD
16115 * @param {Object} the object to evaluate
16116 * @return {boolean} true if typeof oDD = DragDrop
16119 isTypeOfDD: function (oDD) {
16120 return (oDD && oDD.__ygDragDrop);
16124 * Utility function to determine if a given element has been
16125 * registered as a drag drop handle for the given Drag Drop object.
16127 * @param {String} id the element id to check
16128 * @return {boolean} true if this element is a DragDrop handle, false
16132 isHandle: function(sDDId, sHandleId) {
16133 return ( this.handleIds[sDDId] &&
16134 this.handleIds[sDDId][sHandleId] );
16138 * Returns the DragDrop instance for a given id
16139 * @method getDDById
16140 * @param {String} id the id of the DragDrop object
16141 * @return {DragDrop} the drag drop object, null if it is not found
16144 getDDById: function(id) {
16145 for (var i in this.ids) {
16146 if (this.ids[i][id]) {
16147 return this.ids[i][id];
16154 * Fired after a registered DragDrop object gets the mousedown event.
16155 * Sets up the events required to track the object being dragged
16156 * @method handleMouseDown
16157 * @param {Event} e the event
16158 * @param oDD the DragDrop object being dragged
16162 handleMouseDown: function(e, oDD) {
16164 Roo.QuickTips.disable();
16166 this.currentTarget = e.getTarget();
16168 this.dragCurrent = oDD;
16170 var el = oDD.getEl();
16172 // track start position
16173 this.startX = e.getPageX();
16174 this.startY = e.getPageY();
16176 this.deltaX = this.startX - el.offsetLeft;
16177 this.deltaY = this.startY - el.offsetTop;
16179 this.dragThreshMet = false;
16181 this.clickTimeout = setTimeout(
16183 var DDM = Roo.dd.DDM;
16184 DDM.startDrag(DDM.startX, DDM.startY);
16186 this.clickTimeThresh );
16190 * Fired when either the drag pixel threshol or the mousedown hold
16191 * time threshold has been met.
16192 * @method startDrag
16193 * @param x {int} the X position of the original mousedown
16194 * @param y {int} the Y position of the original mousedown
16197 startDrag: function(x, y) {
16198 clearTimeout(this.clickTimeout);
16199 if (this.dragCurrent) {
16200 this.dragCurrent.b4StartDrag(x, y);
16201 this.dragCurrent.startDrag(x, y);
16203 this.dragThreshMet = true;
16207 * Internal function to handle the mouseup event. Will be invoked
16208 * from the context of the document.
16209 * @method handleMouseUp
16210 * @param {Event} e the event
16214 handleMouseUp: function(e) {
16217 Roo.QuickTips.enable();
16219 if (! this.dragCurrent) {
16223 clearTimeout(this.clickTimeout);
16225 if (this.dragThreshMet) {
16226 this.fireEvents(e, true);
16236 * Utility to stop event propagation and event default, if these
16237 * features are turned on.
16238 * @method stopEvent
16239 * @param {Event} e the event as returned by this.getEvent()
16242 stopEvent: function(e){
16243 if(this.stopPropagation) {
16244 e.stopPropagation();
16247 if (this.preventDefault) {
16248 e.preventDefault();
16253 * Internal function to clean up event handlers after the drag
16254 * operation is complete
16256 * @param {Event} e the event
16260 stopDrag: function(e) {
16261 // Fire the drag end event for the item that was dragged
16262 if (this.dragCurrent) {
16263 if (this.dragThreshMet) {
16264 this.dragCurrent.b4EndDrag(e);
16265 this.dragCurrent.endDrag(e);
16268 this.dragCurrent.onMouseUp(e);
16271 this.dragCurrent = null;
16272 this.dragOvers = {};
16276 * Internal function to handle the mousemove event. Will be invoked
16277 * from the context of the html element.
16279 * @TODO figure out what we can do about mouse events lost when the
16280 * user drags objects beyond the window boundary. Currently we can
16281 * detect this in internet explorer by verifying that the mouse is
16282 * down during the mousemove event. Firefox doesn't give us the
16283 * button state on the mousemove event.
16284 * @method handleMouseMove
16285 * @param {Event} e the event
16289 handleMouseMove: function(e) {
16290 if (! this.dragCurrent) {
16294 // var button = e.which || e.button;
16296 // check for IE mouseup outside of page boundary
16297 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16299 return this.handleMouseUp(e);
16302 if (!this.dragThreshMet) {
16303 var diffX = Math.abs(this.startX - e.getPageX());
16304 var diffY = Math.abs(this.startY - e.getPageY());
16305 if (diffX > this.clickPixelThresh ||
16306 diffY > this.clickPixelThresh) {
16307 this.startDrag(this.startX, this.startY);
16311 if (this.dragThreshMet) {
16312 this.dragCurrent.b4Drag(e);
16313 this.dragCurrent.onDrag(e);
16314 if(!this.dragCurrent.moveOnly){
16315 this.fireEvents(e, false);
16325 * Iterates over all of the DragDrop elements to find ones we are
16326 * hovering over or dropping on
16327 * @method fireEvents
16328 * @param {Event} e the event
16329 * @param {boolean} isDrop is this a drop op or a mouseover op?
16333 fireEvents: function(e, isDrop) {
16334 var dc = this.dragCurrent;
16336 // If the user did the mouse up outside of the window, we could
16337 // get here even though we have ended the drag.
16338 if (!dc || dc.isLocked()) {
16342 var pt = e.getPoint();
16344 // cache the previous dragOver array
16350 var enterEvts = [];
16352 // Check to see if the object(s) we were hovering over is no longer
16353 // being hovered over so we can fire the onDragOut event
16354 for (var i in this.dragOvers) {
16356 var ddo = this.dragOvers[i];
16358 if (! this.isTypeOfDD(ddo)) {
16362 if (! this.isOverTarget(pt, ddo, this.mode)) {
16363 outEvts.push( ddo );
16366 oldOvers[i] = true;
16367 delete this.dragOvers[i];
16370 for (var sGroup in dc.groups) {
16372 if ("string" != typeof sGroup) {
16376 for (i in this.ids[sGroup]) {
16377 var oDD = this.ids[sGroup][i];
16378 if (! this.isTypeOfDD(oDD)) {
16382 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16383 if (this.isOverTarget(pt, oDD, this.mode)) {
16384 // look for drop interactions
16386 dropEvts.push( oDD );
16387 // look for drag enter and drag over interactions
16390 // initial drag over: dragEnter fires
16391 if (!oldOvers[oDD.id]) {
16392 enterEvts.push( oDD );
16393 // subsequent drag overs: dragOver fires
16395 overEvts.push( oDD );
16398 this.dragOvers[oDD.id] = oDD;
16406 if (outEvts.length) {
16407 dc.b4DragOut(e, outEvts);
16408 dc.onDragOut(e, outEvts);
16411 if (enterEvts.length) {
16412 dc.onDragEnter(e, enterEvts);
16415 if (overEvts.length) {
16416 dc.b4DragOver(e, overEvts);
16417 dc.onDragOver(e, overEvts);
16420 if (dropEvts.length) {
16421 dc.b4DragDrop(e, dropEvts);
16422 dc.onDragDrop(e, dropEvts);
16426 // fire dragout events
16428 for (i=0, len=outEvts.length; i<len; ++i) {
16429 dc.b4DragOut(e, outEvts[i].id);
16430 dc.onDragOut(e, outEvts[i].id);
16433 // fire enter events
16434 for (i=0,len=enterEvts.length; i<len; ++i) {
16435 // dc.b4DragEnter(e, oDD.id);
16436 dc.onDragEnter(e, enterEvts[i].id);
16439 // fire over events
16440 for (i=0,len=overEvts.length; i<len; ++i) {
16441 dc.b4DragOver(e, overEvts[i].id);
16442 dc.onDragOver(e, overEvts[i].id);
16445 // fire drop events
16446 for (i=0, len=dropEvts.length; i<len; ++i) {
16447 dc.b4DragDrop(e, dropEvts[i].id);
16448 dc.onDragDrop(e, dropEvts[i].id);
16453 // notify about a drop that did not find a target
16454 if (isDrop && !dropEvts.length) {
16455 dc.onInvalidDrop(e);
16461 * Helper function for getting the best match from the list of drag
16462 * and drop objects returned by the drag and drop events when we are
16463 * in INTERSECT mode. It returns either the first object that the
16464 * cursor is over, or the object that has the greatest overlap with
16465 * the dragged element.
16466 * @method getBestMatch
16467 * @param {DragDrop[]} dds The array of drag and drop objects
16469 * @return {DragDrop} The best single match
16472 getBestMatch: function(dds) {
16474 // Return null if the input is not what we expect
16475 //if (!dds || !dds.length || dds.length == 0) {
16477 // If there is only one item, it wins
16478 //} else if (dds.length == 1) {
16480 var len = dds.length;
16485 // Loop through the targeted items
16486 for (var i=0; i<len; ++i) {
16488 // If the cursor is over the object, it wins. If the
16489 // cursor is over multiple matches, the first one we come
16491 if (dd.cursorIsOver) {
16494 // Otherwise the object with the most overlap wins
16497 winner.overlap.getArea() < dd.overlap.getArea()) {
16508 * Refreshes the cache of the top-left and bottom-right points of the
16509 * drag and drop objects in the specified group(s). This is in the
16510 * format that is stored in the drag and drop instance, so typical
16513 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16517 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16519 * @TODO this really should be an indexed array. Alternatively this
16520 * method could accept both.
16521 * @method refreshCache
16522 * @param {Object} groups an associative array of groups to refresh
16525 refreshCache: function(groups) {
16526 for (var sGroup in groups) {
16527 if ("string" != typeof sGroup) {
16530 for (var i in this.ids[sGroup]) {
16531 var oDD = this.ids[sGroup][i];
16533 if (this.isTypeOfDD(oDD)) {
16534 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16535 var loc = this.getLocation(oDD);
16537 this.locationCache[oDD.id] = loc;
16539 delete this.locationCache[oDD.id];
16540 // this will unregister the drag and drop object if
16541 // the element is not in a usable state
16550 * This checks to make sure an element exists and is in the DOM. The
16551 * main purpose is to handle cases where innerHTML is used to remove
16552 * drag and drop objects from the DOM. IE provides an 'unspecified
16553 * error' when trying to access the offsetParent of such an element
16555 * @param {HTMLElement} el the element to check
16556 * @return {boolean} true if the element looks usable
16559 verifyEl: function(el) {
16564 parent = el.offsetParent;
16567 parent = el.offsetParent;
16578 * Returns a Region object containing the drag and drop element's position
16579 * and size, including the padding configured for it
16580 * @method getLocation
16581 * @param {DragDrop} oDD the drag and drop object to get the
16583 * @return {Roo.lib.Region} a Region object representing the total area
16584 * the element occupies, including any padding
16585 * the instance is configured for.
16588 getLocation: function(oDD) {
16589 if (! this.isTypeOfDD(oDD)) {
16593 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16596 pos= Roo.lib.Dom.getXY(el);
16604 x2 = x1 + el.offsetWidth;
16606 y2 = y1 + el.offsetHeight;
16608 t = y1 - oDD.padding[0];
16609 r = x2 + oDD.padding[1];
16610 b = y2 + oDD.padding[2];
16611 l = x1 - oDD.padding[3];
16613 return new Roo.lib.Region( t, r, b, l );
16617 * Checks the cursor location to see if it over the target
16618 * @method isOverTarget
16619 * @param {Roo.lib.Point} pt The point to evaluate
16620 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16621 * @return {boolean} true if the mouse is over the target
16625 isOverTarget: function(pt, oTarget, intersect) {
16626 // use cache if available
16627 var loc = this.locationCache[oTarget.id];
16628 if (!loc || !this.useCache) {
16629 loc = this.getLocation(oTarget);
16630 this.locationCache[oTarget.id] = loc;
16638 oTarget.cursorIsOver = loc.contains( pt );
16640 // DragDrop is using this as a sanity check for the initial mousedown
16641 // in this case we are done. In POINT mode, if the drag obj has no
16642 // contraints, we are also done. Otherwise we need to evaluate the
16643 // location of the target as related to the actual location of the
16644 // dragged element.
16645 var dc = this.dragCurrent;
16646 if (!dc || !dc.getTargetCoord ||
16647 (!intersect && !dc.constrainX && !dc.constrainY)) {
16648 return oTarget.cursorIsOver;
16651 oTarget.overlap = null;
16653 // Get the current location of the drag element, this is the
16654 // location of the mouse event less the delta that represents
16655 // where the original mousedown happened on the element. We
16656 // need to consider constraints and ticks as well.
16657 var pos = dc.getTargetCoord(pt.x, pt.y);
16659 var el = dc.getDragEl();
16660 var curRegion = new Roo.lib.Region( pos.y,
16661 pos.x + el.offsetWidth,
16662 pos.y + el.offsetHeight,
16665 var overlap = curRegion.intersect(loc);
16668 oTarget.overlap = overlap;
16669 return (intersect) ? true : oTarget.cursorIsOver;
16676 * unload event handler
16677 * @method _onUnload
16681 _onUnload: function(e, me) {
16682 Roo.dd.DragDropMgr.unregAll();
16686 * Cleans up the drag and drop events and objects.
16691 unregAll: function() {
16693 if (this.dragCurrent) {
16695 this.dragCurrent = null;
16698 this._execOnAll("unreg", []);
16700 for (i in this.elementCache) {
16701 delete this.elementCache[i];
16704 this.elementCache = {};
16709 * A cache of DOM elements
16710 * @property elementCache
16717 * Get the wrapper for the DOM element specified
16718 * @method getElWrapper
16719 * @param {String} id the id of the element to get
16720 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16722 * @deprecated This wrapper isn't that useful
16725 getElWrapper: function(id) {
16726 var oWrapper = this.elementCache[id];
16727 if (!oWrapper || !oWrapper.el) {
16728 oWrapper = this.elementCache[id] =
16729 new this.ElementWrapper(Roo.getDom(id));
16735 * Returns the actual DOM element
16736 * @method getElement
16737 * @param {String} id the id of the elment to get
16738 * @return {Object} The element
16739 * @deprecated use Roo.getDom instead
16742 getElement: function(id) {
16743 return Roo.getDom(id);
16747 * Returns the style property for the DOM element (i.e.,
16748 * document.getElById(id).style)
16750 * @param {String} id the id of the elment to get
16751 * @return {Object} The style property of the element
16752 * @deprecated use Roo.getDom instead
16755 getCss: function(id) {
16756 var el = Roo.getDom(id);
16757 return (el) ? el.style : null;
16761 * Inner class for cached elements
16762 * @class DragDropMgr.ElementWrapper
16767 ElementWrapper: function(el) {
16772 this.el = el || null;
16777 this.id = this.el && el.id;
16779 * A reference to the style property
16782 this.css = this.el && el.style;
16786 * Returns the X position of an html element
16788 * @param el the element for which to get the position
16789 * @return {int} the X coordinate
16791 * @deprecated use Roo.lib.Dom.getX instead
16794 getPosX: function(el) {
16795 return Roo.lib.Dom.getX(el);
16799 * Returns the Y position of an html element
16801 * @param el the element for which to get the position
16802 * @return {int} the Y coordinate
16803 * @deprecated use Roo.lib.Dom.getY instead
16806 getPosY: function(el) {
16807 return Roo.lib.Dom.getY(el);
16811 * Swap two nodes. In IE, we use the native method, for others we
16812 * emulate the IE behavior
16814 * @param n1 the first node to swap
16815 * @param n2 the other node to swap
16818 swapNode: function(n1, n2) {
16822 var p = n2.parentNode;
16823 var s = n2.nextSibling;
16826 p.insertBefore(n1, n2);
16827 } else if (n2 == n1.nextSibling) {
16828 p.insertBefore(n2, n1);
16830 n1.parentNode.replaceChild(n2, n1);
16831 p.insertBefore(n1, s);
16837 * Returns the current scroll position
16838 * @method getScroll
16842 getScroll: function () {
16843 var t, l, dde=document.documentElement, db=document.body;
16844 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16846 l = dde.scrollLeft;
16853 return { top: t, left: l };
16857 * Returns the specified element style property
16859 * @param {HTMLElement} el the element
16860 * @param {string} styleProp the style property
16861 * @return {string} The value of the style property
16862 * @deprecated use Roo.lib.Dom.getStyle
16865 getStyle: function(el, styleProp) {
16866 return Roo.fly(el).getStyle(styleProp);
16870 * Gets the scrollTop
16871 * @method getScrollTop
16872 * @return {int} the document's scrollTop
16875 getScrollTop: function () { return this.getScroll().top; },
16878 * Gets the scrollLeft
16879 * @method getScrollLeft
16880 * @return {int} the document's scrollTop
16883 getScrollLeft: function () { return this.getScroll().left; },
16886 * Sets the x/y position of an element to the location of the
16889 * @param {HTMLElement} moveEl The element to move
16890 * @param {HTMLElement} targetEl The position reference element
16893 moveToEl: function (moveEl, targetEl) {
16894 var aCoord = Roo.lib.Dom.getXY(targetEl);
16895 Roo.lib.Dom.setXY(moveEl, aCoord);
16899 * Numeric array sort function
16900 * @method numericSort
16903 numericSort: function(a, b) { return (a - b); },
16907 * @property _timeoutCount
16914 * Trying to make the load order less important. Without this we get
16915 * an error if this file is loaded before the Event Utility.
16916 * @method _addListeners
16920 _addListeners: function() {
16921 var DDM = Roo.dd.DDM;
16922 if ( Roo.lib.Event && document ) {
16925 if (DDM._timeoutCount > 2000) {
16927 setTimeout(DDM._addListeners, 10);
16928 if (document && document.body) {
16929 DDM._timeoutCount += 1;
16936 * Recursively searches the immediate parent and all child nodes for
16937 * the handle element in order to determine wheter or not it was
16939 * @method handleWasClicked
16940 * @param node the html element to inspect
16943 handleWasClicked: function(node, id) {
16944 if (this.isHandle(id, node.id)) {
16947 // check to see if this is a text node child of the one we want
16948 var p = node.parentNode;
16951 if (this.isHandle(id, p.id)) {
16966 // shorter alias, save a few bytes
16967 Roo.dd.DDM = Roo.dd.DragDropMgr;
16968 Roo.dd.DDM._addListeners();
16972 * Ext JS Library 1.1.1
16973 * Copyright(c) 2006-2007, Ext JS, LLC.
16975 * Originally Released Under LGPL - original licence link has changed is not relivant.
16978 * <script type="text/javascript">
16983 * A DragDrop implementation where the linked element follows the
16984 * mouse cursor during a drag.
16985 * @extends Roo.dd.DragDrop
16987 * @param {String} id the id of the linked element
16988 * @param {String} sGroup the group of related DragDrop items
16989 * @param {object} config an object containing configurable attributes
16990 * Valid properties for DD:
16993 Roo.dd.DD = function(id, sGroup, config) {
16995 this.init(id, sGroup, config);
16999 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17002 * When set to true, the utility automatically tries to scroll the browser
17003 * window wehn a drag and drop element is dragged near the viewport boundary.
17004 * Defaults to true.
17011 * Sets the pointer offset to the distance between the linked element's top
17012 * left corner and the location the element was clicked
17013 * @method autoOffset
17014 * @param {int} iPageX the X coordinate of the click
17015 * @param {int} iPageY the Y coordinate of the click
17017 autoOffset: function(iPageX, iPageY) {
17018 var x = iPageX - this.startPageX;
17019 var y = iPageY - this.startPageY;
17020 this.setDelta(x, y);
17024 * Sets the pointer offset. You can call this directly to force the
17025 * offset to be in a particular location (e.g., pass in 0,0 to set it
17026 * to the center of the object)
17028 * @param {int} iDeltaX the distance from the left
17029 * @param {int} iDeltaY the distance from the top
17031 setDelta: function(iDeltaX, iDeltaY) {
17032 this.deltaX = iDeltaX;
17033 this.deltaY = iDeltaY;
17037 * Sets the drag element to the location of the mousedown or click event,
17038 * maintaining the cursor location relative to the location on the element
17039 * that was clicked. Override this if you want to place the element in a
17040 * location other than where the cursor is.
17041 * @method setDragElPos
17042 * @param {int} iPageX the X coordinate of the mousedown or drag event
17043 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17045 setDragElPos: function(iPageX, iPageY) {
17046 // the first time we do this, we are going to check to make sure
17047 // the element has css positioning
17049 var el = this.getDragEl();
17050 this.alignElWithMouse(el, iPageX, iPageY);
17054 * Sets the element to the location of the mousedown or click event,
17055 * maintaining the cursor location relative to the location on the element
17056 * that was clicked. Override this if you want to place the element in a
17057 * location other than where the cursor is.
17058 * @method alignElWithMouse
17059 * @param {HTMLElement} el the element to move
17060 * @param {int} iPageX the X coordinate of the mousedown or drag event
17061 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17063 alignElWithMouse: function(el, iPageX, iPageY) {
17064 var oCoord = this.getTargetCoord(iPageX, iPageY);
17065 var fly = el.dom ? el : Roo.fly(el);
17066 if (!this.deltaSetXY) {
17067 var aCoord = [oCoord.x, oCoord.y];
17069 var newLeft = fly.getLeft(true);
17070 var newTop = fly.getTop(true);
17071 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17073 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17076 this.cachePosition(oCoord.x, oCoord.y);
17077 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17082 * Saves the most recent position so that we can reset the constraints and
17083 * tick marks on-demand. We need to know this so that we can calculate the
17084 * number of pixels the element is offset from its original position.
17085 * @method cachePosition
17086 * @param iPageX the current x position (optional, this just makes it so we
17087 * don't have to look it up again)
17088 * @param iPageY the current y position (optional, this just makes it so we
17089 * don't have to look it up again)
17091 cachePosition: function(iPageX, iPageY) {
17093 this.lastPageX = iPageX;
17094 this.lastPageY = iPageY;
17096 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17097 this.lastPageX = aCoord[0];
17098 this.lastPageY = aCoord[1];
17103 * Auto-scroll the window if the dragged object has been moved beyond the
17104 * visible window boundary.
17105 * @method autoScroll
17106 * @param {int} x the drag element's x position
17107 * @param {int} y the drag element's y position
17108 * @param {int} h the height of the drag element
17109 * @param {int} w the width of the drag element
17112 autoScroll: function(x, y, h, w) {
17115 // The client height
17116 var clientH = Roo.lib.Dom.getViewWidth();
17118 // The client width
17119 var clientW = Roo.lib.Dom.getViewHeight();
17121 // The amt scrolled down
17122 var st = this.DDM.getScrollTop();
17124 // The amt scrolled right
17125 var sl = this.DDM.getScrollLeft();
17127 // Location of the bottom of the element
17130 // Location of the right of the element
17133 // The distance from the cursor to the bottom of the visible area,
17134 // adjusted so that we don't scroll if the cursor is beyond the
17135 // element drag constraints
17136 var toBot = (clientH + st - y - this.deltaY);
17138 // The distance from the cursor to the right of the visible area
17139 var toRight = (clientW + sl - x - this.deltaX);
17142 // How close to the edge the cursor must be before we scroll
17143 // var thresh = (document.all) ? 100 : 40;
17146 // How many pixels to scroll per autoscroll op. This helps to reduce
17147 // clunky scrolling. IE is more sensitive about this ... it needs this
17148 // value to be higher.
17149 var scrAmt = (document.all) ? 80 : 30;
17151 // Scroll down if we are near the bottom of the visible page and the
17152 // obj extends below the crease
17153 if ( bot > clientH && toBot < thresh ) {
17154 window.scrollTo(sl, st + scrAmt);
17157 // Scroll up if the window is scrolled down and the top of the object
17158 // goes above the top border
17159 if ( y < st && st > 0 && y - st < thresh ) {
17160 window.scrollTo(sl, st - scrAmt);
17163 // Scroll right if the obj is beyond the right border and the cursor is
17164 // near the border.
17165 if ( right > clientW && toRight < thresh ) {
17166 window.scrollTo(sl + scrAmt, st);
17169 // Scroll left if the window has been scrolled to the right and the obj
17170 // extends past the left border
17171 if ( x < sl && sl > 0 && x - sl < thresh ) {
17172 window.scrollTo(sl - scrAmt, st);
17178 * Finds the location the element should be placed if we want to move
17179 * it to where the mouse location less the click offset would place us.
17180 * @method getTargetCoord
17181 * @param {int} iPageX the X coordinate of the click
17182 * @param {int} iPageY the Y coordinate of the click
17183 * @return an object that contains the coordinates (Object.x and Object.y)
17186 getTargetCoord: function(iPageX, iPageY) {
17189 var x = iPageX - this.deltaX;
17190 var y = iPageY - this.deltaY;
17192 if (this.constrainX) {
17193 if (x < this.minX) { x = this.minX; }
17194 if (x > this.maxX) { x = this.maxX; }
17197 if (this.constrainY) {
17198 if (y < this.minY) { y = this.minY; }
17199 if (y > this.maxY) { y = this.maxY; }
17202 x = this.getTick(x, this.xTicks);
17203 y = this.getTick(y, this.yTicks);
17210 * Sets up config options specific to this class. Overrides
17211 * Roo.dd.DragDrop, but all versions of this method through the
17212 * inheritance chain are called
17214 applyConfig: function() {
17215 Roo.dd.DD.superclass.applyConfig.call(this);
17216 this.scroll = (this.config.scroll !== false);
17220 * Event that fires prior to the onMouseDown event. Overrides
17223 b4MouseDown: function(e) {
17224 // this.resetConstraints();
17225 this.autoOffset(e.getPageX(),
17230 * Event that fires prior to the onDrag event. Overrides
17233 b4Drag: function(e) {
17234 this.setDragElPos(e.getPageX(),
17238 toString: function() {
17239 return ("DD " + this.id);
17242 //////////////////////////////////////////////////////////////////////////
17243 // Debugging ygDragDrop events that can be overridden
17244 //////////////////////////////////////////////////////////////////////////
17246 startDrag: function(x, y) {
17249 onDrag: function(e) {
17252 onDragEnter: function(e, id) {
17255 onDragOver: function(e, id) {
17258 onDragOut: function(e, id) {
17261 onDragDrop: function(e, id) {
17264 endDrag: function(e) {
17271 * Ext JS Library 1.1.1
17272 * Copyright(c) 2006-2007, Ext JS, LLC.
17274 * Originally Released Under LGPL - original licence link has changed is not relivant.
17277 * <script type="text/javascript">
17281 * @class Roo.dd.DDProxy
17282 * A DragDrop implementation that inserts an empty, bordered div into
17283 * the document that follows the cursor during drag operations. At the time of
17284 * the click, the frame div is resized to the dimensions of the linked html
17285 * element, and moved to the exact location of the linked element.
17287 * References to the "frame" element refer to the single proxy element that
17288 * was created to be dragged in place of all DDProxy elements on the
17291 * @extends Roo.dd.DD
17293 * @param {String} id the id of the linked html element
17294 * @param {String} sGroup the group of related DragDrop objects
17295 * @param {object} config an object containing configurable attributes
17296 * Valid properties for DDProxy in addition to those in DragDrop:
17297 * resizeFrame, centerFrame, dragElId
17299 Roo.dd.DDProxy = function(id, sGroup, config) {
17301 this.init(id, sGroup, config);
17307 * The default drag frame div id
17308 * @property Roo.dd.DDProxy.dragElId
17312 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17314 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17317 * By default we resize the drag frame to be the same size as the element
17318 * we want to drag (this is to get the frame effect). We can turn it off
17319 * if we want a different behavior.
17320 * @property resizeFrame
17326 * By default the frame is positioned exactly where the drag element is, so
17327 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17328 * you do not have constraints on the obj is to have the drag frame centered
17329 * around the cursor. Set centerFrame to true for this effect.
17330 * @property centerFrame
17333 centerFrame: false,
17336 * Creates the proxy element if it does not yet exist
17337 * @method createFrame
17339 createFrame: function() {
17341 var body = document.body;
17343 if (!body || !body.firstChild) {
17344 setTimeout( function() { self.createFrame(); }, 50 );
17348 var div = this.getDragEl();
17351 div = document.createElement("div");
17352 div.id = this.dragElId;
17355 s.position = "absolute";
17356 s.visibility = "hidden";
17358 s.border = "2px solid #aaa";
17361 // appendChild can blow up IE if invoked prior to the window load event
17362 // while rendering a table. It is possible there are other scenarios
17363 // that would cause this to happen as well.
17364 body.insertBefore(div, body.firstChild);
17369 * Initialization for the drag frame element. Must be called in the
17370 * constructor of all subclasses
17371 * @method initFrame
17373 initFrame: function() {
17374 this.createFrame();
17377 applyConfig: function() {
17378 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17380 this.resizeFrame = (this.config.resizeFrame !== false);
17381 this.centerFrame = (this.config.centerFrame);
17382 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17386 * Resizes the drag frame to the dimensions of the clicked object, positions
17387 * it over the object, and finally displays it
17388 * @method showFrame
17389 * @param {int} iPageX X click position
17390 * @param {int} iPageY Y click position
17393 showFrame: function(iPageX, iPageY) {
17394 var el = this.getEl();
17395 var dragEl = this.getDragEl();
17396 var s = dragEl.style;
17398 this._resizeProxy();
17400 if (this.centerFrame) {
17401 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17402 Math.round(parseInt(s.height, 10)/2) );
17405 this.setDragElPos(iPageX, iPageY);
17407 Roo.fly(dragEl).show();
17411 * The proxy is automatically resized to the dimensions of the linked
17412 * element when a drag is initiated, unless resizeFrame is set to false
17413 * @method _resizeProxy
17416 _resizeProxy: function() {
17417 if (this.resizeFrame) {
17418 var el = this.getEl();
17419 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17423 // overrides Roo.dd.DragDrop
17424 b4MouseDown: function(e) {
17425 var x = e.getPageX();
17426 var y = e.getPageY();
17427 this.autoOffset(x, y);
17428 this.setDragElPos(x, y);
17431 // overrides Roo.dd.DragDrop
17432 b4StartDrag: function(x, y) {
17433 // show the drag frame
17434 this.showFrame(x, y);
17437 // overrides Roo.dd.DragDrop
17438 b4EndDrag: function(e) {
17439 Roo.fly(this.getDragEl()).hide();
17442 // overrides Roo.dd.DragDrop
17443 // By default we try to move the element to the last location of the frame.
17444 // This is so that the default behavior mirrors that of Roo.dd.DD.
17445 endDrag: function(e) {
17447 var lel = this.getEl();
17448 var del = this.getDragEl();
17450 // Show the drag frame briefly so we can get its position
17451 del.style.visibility = "";
17454 // Hide the linked element before the move to get around a Safari
17456 lel.style.visibility = "hidden";
17457 Roo.dd.DDM.moveToEl(lel, del);
17458 del.style.visibility = "hidden";
17459 lel.style.visibility = "";
17464 beforeMove : function(){
17468 afterDrag : function(){
17472 toString: function() {
17473 return ("DDProxy " + this.id);
17479 * Ext JS Library 1.1.1
17480 * Copyright(c) 2006-2007, Ext JS, LLC.
17482 * Originally Released Under LGPL - original licence link has changed is not relivant.
17485 * <script type="text/javascript">
17489 * @class Roo.dd.DDTarget
17490 * A DragDrop implementation that does not move, but can be a drop
17491 * target. You would get the same result by simply omitting implementation
17492 * for the event callbacks, but this way we reduce the processing cost of the
17493 * event listener and the callbacks.
17494 * @extends Roo.dd.DragDrop
17496 * @param {String} id the id of the element that is a drop target
17497 * @param {String} sGroup the group of related DragDrop objects
17498 * @param {object} config an object containing configurable attributes
17499 * Valid properties for DDTarget in addition to those in
17503 Roo.dd.DDTarget = function(id, sGroup, config) {
17505 this.initTarget(id, sGroup, config);
17507 if (config.listeners || config.events) {
17508 Roo.dd.DragDrop.superclass.constructor.call(this, {
17509 listeners : config.listeners || {},
17510 events : config.events || {}
17515 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17516 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17517 toString: function() {
17518 return ("DDTarget " + this.id);
17523 * Ext JS Library 1.1.1
17524 * Copyright(c) 2006-2007, Ext JS, LLC.
17526 * Originally Released Under LGPL - original licence link has changed is not relivant.
17529 * <script type="text/javascript">
17534 * @class Roo.dd.ScrollManager
17535 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17536 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17539 Roo.dd.ScrollManager = function(){
17540 var ddm = Roo.dd.DragDropMgr;
17545 var onStop = function(e){
17550 var triggerRefresh = function(){
17551 if(ddm.dragCurrent){
17552 ddm.refreshCache(ddm.dragCurrent.groups);
17556 var doScroll = function(){
17557 if(ddm.dragCurrent){
17558 var dds = Roo.dd.ScrollManager;
17560 if(proc.el.scroll(proc.dir, dds.increment)){
17564 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17569 var clearProc = function(){
17571 clearInterval(proc.id);
17578 var startProc = function(el, dir){
17582 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17585 var onFire = function(e, isDrop){
17586 if(isDrop || !ddm.dragCurrent){ return; }
17587 var dds = Roo.dd.ScrollManager;
17588 if(!dragEl || dragEl != ddm.dragCurrent){
17589 dragEl = ddm.dragCurrent;
17590 // refresh regions on drag start
17591 dds.refreshCache();
17594 var xy = Roo.lib.Event.getXY(e);
17595 var pt = new Roo.lib.Point(xy[0], xy[1]);
17596 for(var id in els){
17597 var el = els[id], r = el._region;
17598 if(r && r.contains(pt) && el.isScrollable()){
17599 if(r.bottom - pt.y <= dds.thresh){
17601 startProc(el, "down");
17604 }else if(r.right - pt.x <= dds.thresh){
17606 startProc(el, "left");
17609 }else if(pt.y - r.top <= dds.thresh){
17611 startProc(el, "up");
17614 }else if(pt.x - r.left <= dds.thresh){
17616 startProc(el, "right");
17625 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17626 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17630 * Registers new overflow element(s) to auto scroll
17631 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17633 register : function(el){
17634 if(el instanceof Array){
17635 for(var i = 0, len = el.length; i < len; i++) {
17636 this.register(el[i]);
17645 * Unregisters overflow element(s) so they are no longer scrolled
17646 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17648 unregister : function(el){
17649 if(el instanceof Array){
17650 for(var i = 0, len = el.length; i < len; i++) {
17651 this.unregister(el[i]);
17660 * The number of pixels from the edge of a container the pointer needs to be to
17661 * trigger scrolling (defaults to 25)
17667 * The number of pixels to scroll in each scroll increment (defaults to 50)
17673 * The frequency of scrolls in milliseconds (defaults to 500)
17679 * True to animate the scroll (defaults to true)
17685 * The animation duration in seconds -
17686 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17692 * Manually trigger a cache refresh.
17694 refreshCache : function(){
17695 for(var id in els){
17696 if(typeof els[id] == 'object'){ // for people extending the object prototype
17697 els[id]._region = els[id].getRegion();
17704 * Ext JS Library 1.1.1
17705 * Copyright(c) 2006-2007, Ext JS, LLC.
17707 * Originally Released Under LGPL - original licence link has changed is not relivant.
17710 * <script type="text/javascript">
17715 * @class Roo.dd.Registry
17716 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17717 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17720 Roo.dd.Registry = function(){
17723 var autoIdSeed = 0;
17725 var getId = function(el, autogen){
17726 if(typeof el == "string"){
17730 if(!id && autogen !== false){
17731 id = "roodd-" + (++autoIdSeed);
17739 * Register a drag drop element
17740 * @param {String|HTMLElement} element The id or DOM node to register
17741 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17742 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17743 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17744 * populated in the data object (if applicable):
17746 Value Description<br />
17747 --------- ------------------------------------------<br />
17748 handles Array of DOM nodes that trigger dragging<br />
17749 for the element being registered<br />
17750 isHandle True if the element passed in triggers<br />
17751 dragging itself, else false
17754 register : function(el, data){
17756 if(typeof el == "string"){
17757 el = document.getElementById(el);
17760 elements[getId(el)] = data;
17761 if(data.isHandle !== false){
17762 handles[data.ddel.id] = data;
17765 var hs = data.handles;
17766 for(var i = 0, len = hs.length; i < len; i++){
17767 handles[getId(hs[i])] = data;
17773 * Unregister a drag drop element
17774 * @param {String|HTMLElement} element The id or DOM node to unregister
17776 unregister : function(el){
17777 var id = getId(el, false);
17778 var data = elements[id];
17780 delete elements[id];
17782 var hs = data.handles;
17783 for(var i = 0, len = hs.length; i < len; i++){
17784 delete handles[getId(hs[i], false)];
17791 * Returns the handle registered for a DOM Node by id
17792 * @param {String|HTMLElement} id The DOM node or id to look up
17793 * @return {Object} handle The custom handle data
17795 getHandle : function(id){
17796 if(typeof id != "string"){ // must be element?
17799 return handles[id];
17803 * Returns the handle that is registered for the DOM node that is the target of the event
17804 * @param {Event} e The event
17805 * @return {Object} handle The custom handle data
17807 getHandleFromEvent : function(e){
17808 var t = Roo.lib.Event.getTarget(e);
17809 return t ? handles[t.id] : null;
17813 * Returns a custom data object that is registered for a DOM node by id
17814 * @param {String|HTMLElement} id The DOM node or id to look up
17815 * @return {Object} data The custom data
17817 getTarget : function(id){
17818 if(typeof id != "string"){ // must be element?
17821 return elements[id];
17825 * Returns a custom data object that is registered for the DOM node that is the target of the event
17826 * @param {Event} e The event
17827 * @return {Object} data The custom data
17829 getTargetFromEvent : function(e){
17830 var t = Roo.lib.Event.getTarget(e);
17831 return t ? elements[t.id] || handles[t.id] : null;
17836 * Ext JS Library 1.1.1
17837 * Copyright(c) 2006-2007, Ext JS, LLC.
17839 * Originally Released Under LGPL - original licence link has changed is not relivant.
17842 * <script type="text/javascript">
17847 * @class Roo.dd.StatusProxy
17848 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17849 * default drag proxy used by all Roo.dd components.
17851 * @param {Object} config
17853 Roo.dd.StatusProxy = function(config){
17854 Roo.apply(this, config);
17855 this.id = this.id || Roo.id();
17856 this.el = new Roo.Layer({
17858 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17859 {tag: "div", cls: "x-dd-drop-icon"},
17860 {tag: "div", cls: "x-dd-drag-ghost"}
17863 shadow: !config || config.shadow !== false
17865 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17866 this.dropStatus = this.dropNotAllowed;
17869 Roo.dd.StatusProxy.prototype = {
17871 * @cfg {String} dropAllowed
17872 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17874 dropAllowed : "x-dd-drop-ok",
17876 * @cfg {String} dropNotAllowed
17877 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17879 dropNotAllowed : "x-dd-drop-nodrop",
17882 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17883 * over the current target element.
17884 * @param {String} cssClass The css class for the new drop status indicator image
17886 setStatus : function(cssClass){
17887 cssClass = cssClass || this.dropNotAllowed;
17888 if(this.dropStatus != cssClass){
17889 this.el.replaceClass(this.dropStatus, cssClass);
17890 this.dropStatus = cssClass;
17895 * Resets the status indicator to the default dropNotAllowed value
17896 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17898 reset : function(clearGhost){
17899 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17900 this.dropStatus = this.dropNotAllowed;
17902 this.ghost.update("");
17907 * Updates the contents of the ghost element
17908 * @param {String} html The html that will replace the current innerHTML of the ghost element
17910 update : function(html){
17911 if(typeof html == "string"){
17912 this.ghost.update(html);
17914 this.ghost.update("");
17915 html.style.margin = "0";
17916 this.ghost.dom.appendChild(html);
17918 // ensure float = none set?? cant remember why though.
17919 var el = this.ghost.dom.firstChild;
17921 Roo.fly(el).setStyle('float', 'none');
17926 * Returns the underlying proxy {@link Roo.Layer}
17927 * @return {Roo.Layer} el
17929 getEl : function(){
17934 * Returns the ghost element
17935 * @return {Roo.Element} el
17937 getGhost : function(){
17943 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17945 hide : function(clear){
17953 * Stops the repair animation if it's currently running
17956 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17962 * Displays this proxy
17969 * Force the Layer to sync its shadow and shim positions to the element
17976 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17977 * invalid drop operation by the item being dragged.
17978 * @param {Array} xy The XY position of the element ([x, y])
17979 * @param {Function} callback The function to call after the repair is complete
17980 * @param {Object} scope The scope in which to execute the callback
17982 repair : function(xy, callback, scope){
17983 this.callback = callback;
17984 this.scope = scope;
17985 if(xy && this.animRepair !== false){
17986 this.el.addClass("x-dd-drag-repair");
17987 this.el.hideUnders(true);
17988 this.anim = this.el.shift({
17989 duration: this.repairDuration || .5,
17993 callback: this.afterRepair,
17997 this.afterRepair();
18002 afterRepair : function(){
18004 if(typeof this.callback == "function"){
18005 this.callback.call(this.scope || this);
18007 this.callback = null;
18012 * Ext JS Library 1.1.1
18013 * Copyright(c) 2006-2007, Ext JS, LLC.
18015 * Originally Released Under LGPL - original licence link has changed is not relivant.
18018 * <script type="text/javascript">
18022 * @class Roo.dd.DragSource
18023 * @extends Roo.dd.DDProxy
18024 * A simple class that provides the basic implementation needed to make any element draggable.
18026 * @param {String/HTMLElement/Element} el The container element
18027 * @param {Object} config
18029 Roo.dd.DragSource = function(el, config){
18030 this.el = Roo.get(el);
18031 this.dragData = {};
18033 Roo.apply(this, config);
18036 this.proxy = new Roo.dd.StatusProxy();
18039 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18040 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18042 this.dragging = false;
18045 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18047 * @cfg {String} dropAllowed
18048 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18050 dropAllowed : "x-dd-drop-ok",
18052 * @cfg {String} dropNotAllowed
18053 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18055 dropNotAllowed : "x-dd-drop-nodrop",
18058 * Returns the data object associated with this drag source
18059 * @return {Object} data An object containing arbitrary data
18061 getDragData : function(e){
18062 return this.dragData;
18066 onDragEnter : function(e, id){
18067 var target = Roo.dd.DragDropMgr.getDDById(id);
18068 this.cachedTarget = target;
18069 if(this.beforeDragEnter(target, e, id) !== false){
18070 if(target.isNotifyTarget){
18071 var status = target.notifyEnter(this, e, this.dragData);
18072 this.proxy.setStatus(status);
18074 this.proxy.setStatus(this.dropAllowed);
18077 if(this.afterDragEnter){
18079 * An empty function by default, but provided so that you can perform a custom action
18080 * when the dragged item enters the drop target by providing an implementation.
18081 * @param {Roo.dd.DragDrop} target The drop target
18082 * @param {Event} e The event object
18083 * @param {String} id The id of the dragged element
18084 * @method afterDragEnter
18086 this.afterDragEnter(target, e, id);
18092 * An empty function by default, but provided so that you can perform a custom action
18093 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18094 * @param {Roo.dd.DragDrop} target The drop target
18095 * @param {Event} e The event object
18096 * @param {String} id The id of the dragged element
18097 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18099 beforeDragEnter : function(target, e, id){
18104 alignElWithMouse: function() {
18105 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18110 onDragOver : function(e, id){
18111 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18112 if(this.beforeDragOver(target, e, id) !== false){
18113 if(target.isNotifyTarget){
18114 var status = target.notifyOver(this, e, this.dragData);
18115 this.proxy.setStatus(status);
18118 if(this.afterDragOver){
18120 * An empty function by default, but provided so that you can perform a custom action
18121 * while the dragged item is over the drop target by providing an implementation.
18122 * @param {Roo.dd.DragDrop} target The drop target
18123 * @param {Event} e The event object
18124 * @param {String} id The id of the dragged element
18125 * @method afterDragOver
18127 this.afterDragOver(target, e, id);
18133 * An empty function by default, but provided so that you can perform a custom action
18134 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18135 * @param {Roo.dd.DragDrop} target The drop target
18136 * @param {Event} e The event object
18137 * @param {String} id The id of the dragged element
18138 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18140 beforeDragOver : function(target, e, id){
18145 onDragOut : function(e, id){
18146 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18147 if(this.beforeDragOut(target, e, id) !== false){
18148 if(target.isNotifyTarget){
18149 target.notifyOut(this, e, this.dragData);
18151 this.proxy.reset();
18152 if(this.afterDragOut){
18154 * An empty function by default, but provided so that you can perform a custom action
18155 * after the dragged item is dragged out of the target without dropping.
18156 * @param {Roo.dd.DragDrop} target The drop target
18157 * @param {Event} e The event object
18158 * @param {String} id The id of the dragged element
18159 * @method afterDragOut
18161 this.afterDragOut(target, e, id);
18164 this.cachedTarget = null;
18168 * An empty function by default, but provided so that you can perform a custom action before the dragged
18169 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18170 * @param {Roo.dd.DragDrop} target The drop target
18171 * @param {Event} e The event object
18172 * @param {String} id The id of the dragged element
18173 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18175 beforeDragOut : function(target, e, id){
18180 onDragDrop : function(e, id){
18181 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18182 if(this.beforeDragDrop(target, e, id) !== false){
18183 if(target.isNotifyTarget){
18184 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18185 this.onValidDrop(target, e, id);
18187 this.onInvalidDrop(target, e, id);
18190 this.onValidDrop(target, e, id);
18193 if(this.afterDragDrop){
18195 * An empty function by default, but provided so that you can perform a custom action
18196 * after a valid drag drop has occurred by providing an implementation.
18197 * @param {Roo.dd.DragDrop} target The drop target
18198 * @param {Event} e The event object
18199 * @param {String} id The id of the dropped element
18200 * @method afterDragDrop
18202 this.afterDragDrop(target, e, id);
18205 delete this.cachedTarget;
18209 * An empty function by default, but provided so that you can perform a custom action before the dragged
18210 * item is dropped onto the target and optionally cancel the onDragDrop.
18211 * @param {Roo.dd.DragDrop} target The drop target
18212 * @param {Event} e The event object
18213 * @param {String} id The id of the dragged element
18214 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18216 beforeDragDrop : function(target, e, id){
18221 onValidDrop : function(target, e, id){
18223 if(this.afterValidDrop){
18225 * An empty function by default, but provided so that you can perform a custom action
18226 * after a valid drop has occurred by providing an implementation.
18227 * @param {Object} target The target DD
18228 * @param {Event} e The event object
18229 * @param {String} id The id of the dropped element
18230 * @method afterInvalidDrop
18232 this.afterValidDrop(target, e, id);
18237 getRepairXY : function(e, data){
18238 return this.el.getXY();
18242 onInvalidDrop : function(target, e, id){
18243 this.beforeInvalidDrop(target, e, id);
18244 if(this.cachedTarget){
18245 if(this.cachedTarget.isNotifyTarget){
18246 this.cachedTarget.notifyOut(this, e, this.dragData);
18248 this.cacheTarget = null;
18250 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18252 if(this.afterInvalidDrop){
18254 * An empty function by default, but provided so that you can perform a custom action
18255 * after an invalid drop has occurred by providing an implementation.
18256 * @param {Event} e The event object
18257 * @param {String} id The id of the dropped element
18258 * @method afterInvalidDrop
18260 this.afterInvalidDrop(e, id);
18265 afterRepair : function(){
18267 this.el.highlight(this.hlColor || "c3daf9");
18269 this.dragging = false;
18273 * An empty function by default, but provided so that you can perform a custom action after an invalid
18274 * drop has occurred.
18275 * @param {Roo.dd.DragDrop} target The drop target
18276 * @param {Event} e The event object
18277 * @param {String} id The id of the dragged element
18278 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18280 beforeInvalidDrop : function(target, e, id){
18285 handleMouseDown : function(e){
18286 if(this.dragging) {
18289 var data = this.getDragData(e);
18290 if(data && this.onBeforeDrag(data, e) !== false){
18291 this.dragData = data;
18293 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18298 * An empty function by default, but provided so that you can perform a custom action before the initial
18299 * drag event begins and optionally cancel it.
18300 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18301 * @param {Event} e The event object
18302 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18304 onBeforeDrag : function(data, e){
18309 * An empty function by default, but provided so that you can perform a custom action once the initial
18310 * drag event has begun. The drag cannot be canceled from this function.
18311 * @param {Number} x The x position of the click on the dragged object
18312 * @param {Number} y The y position of the click on the dragged object
18314 onStartDrag : Roo.emptyFn,
18316 // private - YUI override
18317 startDrag : function(x, y){
18318 this.proxy.reset();
18319 this.dragging = true;
18320 this.proxy.update("");
18321 this.onInitDrag(x, y);
18326 onInitDrag : function(x, y){
18327 var clone = this.el.dom.cloneNode(true);
18328 clone.id = Roo.id(); // prevent duplicate ids
18329 this.proxy.update(clone);
18330 this.onStartDrag(x, y);
18335 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18336 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18338 getProxy : function(){
18343 * Hides the drag source's {@link Roo.dd.StatusProxy}
18345 hideProxy : function(){
18347 this.proxy.reset(true);
18348 this.dragging = false;
18352 triggerCacheRefresh : function(){
18353 Roo.dd.DDM.refreshCache(this.groups);
18356 // private - override to prevent hiding
18357 b4EndDrag: function(e) {
18360 // private - override to prevent moving
18361 endDrag : function(e){
18362 this.onEndDrag(this.dragData, e);
18366 onEndDrag : function(data, e){
18369 // private - pin to cursor
18370 autoOffset : function(x, y) {
18371 this.setDelta(-12, -20);
18375 * Ext JS Library 1.1.1
18376 * Copyright(c) 2006-2007, Ext JS, LLC.
18378 * Originally Released Under LGPL - original licence link has changed is not relivant.
18381 * <script type="text/javascript">
18386 * @class Roo.dd.DropTarget
18387 * @extends Roo.dd.DDTarget
18388 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18389 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18391 * @param {String/HTMLElement/Element} el The container element
18392 * @param {Object} config
18394 Roo.dd.DropTarget = function(el, config){
18395 this.el = Roo.get(el);
18397 var listeners = false; ;
18398 if (config && config.listeners) {
18399 listeners= config.listeners;
18400 delete config.listeners;
18402 Roo.apply(this, config);
18404 if(this.containerScroll){
18405 Roo.dd.ScrollManager.register(this.el);
18409 * @scope Roo.dd.DropTarget
18414 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18415 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18416 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18418 * IMPORTANT : it should set this.overClass and this.dropAllowed
18420 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18421 * @param {Event} e The event
18422 * @param {Object} data An object containing arbitrary data supplied by the drag source
18428 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18429 * This method will be called on every mouse movement while the drag source is over the drop target.
18430 * This default implementation simply returns the dropAllowed config value.
18432 * IMPORTANT : it should set this.dropAllowed
18434 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18435 * @param {Event} e The event
18436 * @param {Object} data An object containing arbitrary data supplied by the drag source
18442 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18443 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18444 * overClass (if any) from the drop element.
18445 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18446 * @param {Event} e The event
18447 * @param {Object} data An object containing arbitrary data supplied by the drag source
18453 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18454 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18455 * implementation that does something to process the drop event and returns true so that the drag source's
18456 * repair action does not run.
18458 * IMPORTANT : it should set this.success
18460 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18461 * @param {Event} e The event
18462 * @param {Object} data An object containing arbitrary data supplied by the drag source
18468 Roo.dd.DropTarget.superclass.constructor.call( this,
18470 this.ddGroup || this.group,
18473 listeners : listeners || {}
18481 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18483 * @cfg {String} overClass
18484 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18487 * @cfg {String} ddGroup
18488 * The drag drop group to handle drop events for
18492 * @cfg {String} dropAllowed
18493 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18495 dropAllowed : "x-dd-drop-ok",
18497 * @cfg {String} dropNotAllowed
18498 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18500 dropNotAllowed : "x-dd-drop-nodrop",
18502 * @cfg {boolean} success
18503 * set this after drop listener..
18507 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18508 * if the drop point is valid for over/enter..
18515 isNotifyTarget : true,
18520 notifyEnter : function(dd, e, data)
18523 this.fireEvent('enter', dd, e, data);
18524 if(this.overClass){
18525 this.el.addClass(this.overClass);
18527 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18528 this.valid ? this.dropAllowed : this.dropNotAllowed
18535 notifyOver : function(dd, e, data)
18538 this.fireEvent('over', dd, e, data);
18539 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18540 this.valid ? this.dropAllowed : this.dropNotAllowed
18547 notifyOut : function(dd, e, data)
18549 this.fireEvent('out', dd, e, data);
18550 if(this.overClass){
18551 this.el.removeClass(this.overClass);
18558 notifyDrop : function(dd, e, data)
18560 this.success = false;
18561 this.fireEvent('drop', dd, e, data);
18562 return this.success;
18566 * Ext JS Library 1.1.1
18567 * Copyright(c) 2006-2007, Ext JS, LLC.
18569 * Originally Released Under LGPL - original licence link has changed is not relivant.
18572 * <script type="text/javascript">
18577 * @class Roo.dd.DragZone
18578 * @extends Roo.dd.DragSource
18579 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18580 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18582 * @param {String/HTMLElement/Element} el The container element
18583 * @param {Object} config
18585 Roo.dd.DragZone = function(el, config){
18586 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18587 if(this.containerScroll){
18588 Roo.dd.ScrollManager.register(this.el);
18592 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18594 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18595 * for auto scrolling during drag operations.
18598 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18599 * method after a failed drop (defaults to "c3daf9" - light blue)
18603 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18604 * for a valid target to drag based on the mouse down. Override this method
18605 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18606 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18607 * @param {EventObject} e The mouse down event
18608 * @return {Object} The dragData
18610 getDragData : function(e){
18611 return Roo.dd.Registry.getHandleFromEvent(e);
18615 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18616 * this.dragData.ddel
18617 * @param {Number} x The x position of the click on the dragged object
18618 * @param {Number} y The y position of the click on the dragged object
18619 * @return {Boolean} true to continue the drag, false to cancel
18621 onInitDrag : function(x, y){
18622 this.proxy.update(this.dragData.ddel.cloneNode(true));
18623 this.onStartDrag(x, y);
18628 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18630 afterRepair : function(){
18632 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18634 this.dragging = false;
18638 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18639 * the XY of this.dragData.ddel
18640 * @param {EventObject} e The mouse up event
18641 * @return {Array} The xy location (e.g. [100, 200])
18643 getRepairXY : function(e){
18644 return Roo.Element.fly(this.dragData.ddel).getXY();
18648 * Ext JS Library 1.1.1
18649 * Copyright(c) 2006-2007, Ext JS, LLC.
18651 * Originally Released Under LGPL - original licence link has changed is not relivant.
18654 * <script type="text/javascript">
18657 * @class Roo.dd.DropZone
18658 * @extends Roo.dd.DropTarget
18659 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18660 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18662 * @param {String/HTMLElement/Element} el The container element
18663 * @param {Object} config
18665 Roo.dd.DropZone = function(el, config){
18666 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18669 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18671 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18672 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18673 * provide your own custom lookup.
18674 * @param {Event} e The event
18675 * @return {Object} data The custom data
18677 getTargetFromEvent : function(e){
18678 return Roo.dd.Registry.getTargetFromEvent(e);
18682 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18683 * that it has registered. This method has no default implementation and should be overridden to provide
18684 * node-specific processing if necessary.
18685 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18686 * {@link #getTargetFromEvent} for this node)
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
18691 onNodeEnter : function(n, dd, e, data){
18696 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18697 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18698 * overridden to provide the proper feedback.
18699 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18700 * {@link #getTargetFromEvent} for this node)
18701 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18702 * @param {Event} e The event
18703 * @param {Object} data An object containing arbitrary data supplied by the drag source
18704 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18705 * underlying {@link Roo.dd.StatusProxy} can be updated
18707 onNodeOver : function(n, dd, e, data){
18708 return this.dropAllowed;
18712 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18713 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18714 * node-specific processing if necessary.
18715 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18716 * {@link #getTargetFromEvent} for this node)
18717 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18718 * @param {Event} e The event
18719 * @param {Object} data An object containing arbitrary data supplied by the drag source
18721 onNodeOut : function(n, dd, e, data){
18726 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18727 * the drop node. The default implementation returns false, so it should be overridden to provide the
18728 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18729 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18730 * {@link #getTargetFromEvent} for this node)
18731 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18732 * @param {Event} e The event
18733 * @param {Object} data An object containing arbitrary data supplied by the drag source
18734 * @return {Boolean} True if the drop was valid, else false
18736 onNodeDrop : function(n, dd, e, data){
18741 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18742 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18743 * it should be overridden to provide the proper feedback if necessary.
18744 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18745 * @param {Event} e The event
18746 * @param {Object} data An object containing arbitrary data supplied by the drag source
18747 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18748 * underlying {@link Roo.dd.StatusProxy} can be updated
18750 onContainerOver : function(dd, e, data){
18751 return this.dropNotAllowed;
18755 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18756 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18757 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18758 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18759 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18760 * @param {Event} e The event
18761 * @param {Object} data An object containing arbitrary data supplied by the drag source
18762 * @return {Boolean} True if the drop was valid, else false
18764 onContainerDrop : function(dd, e, data){
18769 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18770 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18771 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18772 * you should override this method and provide a custom implementation.
18773 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18774 * @param {Event} e The event
18775 * @param {Object} data An object containing arbitrary data supplied by the drag source
18776 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18777 * underlying {@link Roo.dd.StatusProxy} can be updated
18779 notifyEnter : function(dd, e, data){
18780 return this.dropNotAllowed;
18784 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18785 * This method will be called on every mouse movement while the drag source is over the drop zone.
18786 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18787 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18788 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18789 * registered node, it will call {@link #onContainerOver}.
18790 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18791 * @param {Event} e The event
18792 * @param {Object} data An object containing arbitrary data supplied by the drag source
18793 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18794 * underlying {@link Roo.dd.StatusProxy} can be updated
18796 notifyOver : function(dd, e, data){
18797 var n = this.getTargetFromEvent(e);
18798 if(!n){ // not over valid drop target
18799 if(this.lastOverNode){
18800 this.onNodeOut(this.lastOverNode, dd, e, data);
18801 this.lastOverNode = null;
18803 return this.onContainerOver(dd, e, data);
18805 if(this.lastOverNode != n){
18806 if(this.lastOverNode){
18807 this.onNodeOut(this.lastOverNode, dd, e, data);
18809 this.onNodeEnter(n, dd, e, data);
18810 this.lastOverNode = n;
18812 return this.onNodeOver(n, dd, e, data);
18816 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18817 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18818 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18819 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18820 * @param {Event} e The event
18821 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18823 notifyOut : function(dd, e, data){
18824 if(this.lastOverNode){
18825 this.onNodeOut(this.lastOverNode, dd, e, data);
18826 this.lastOverNode = null;
18831 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18832 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18833 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18834 * otherwise it will call {@link #onContainerDrop}.
18835 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18836 * @param {Event} e The event
18837 * @param {Object} data An object containing arbitrary data supplied by the drag source
18838 * @return {Boolean} True if the drop was valid, else false
18840 notifyDrop : function(dd, e, data){
18841 if(this.lastOverNode){
18842 this.onNodeOut(this.lastOverNode, dd, e, data);
18843 this.lastOverNode = null;
18845 var n = this.getTargetFromEvent(e);
18847 this.onNodeDrop(n, dd, e, data) :
18848 this.onContainerDrop(dd, e, data);
18852 triggerCacheRefresh : function(){
18853 Roo.dd.DDM.refreshCache(this.groups);
18857 * Ext JS Library 1.1.1
18858 * Copyright(c) 2006-2007, Ext JS, LLC.
18860 * Originally Released Under LGPL - original licence link has changed is not relivant.
18863 * <script type="text/javascript">
18868 * @class Roo.data.SortTypes
18870 * Defines the default sorting (casting?) comparison functions used when sorting data.
18872 Roo.data.SortTypes = {
18874 * Default sort that does nothing
18875 * @param {Mixed} s The value being converted
18876 * @return {Mixed} The comparison value
18878 none : function(s){
18883 * The regular expression used to strip tags
18887 stripTagsRE : /<\/?[^>]+>/gi,
18890 * Strips all HTML tags to sort on text only
18891 * @param {Mixed} s The value being converted
18892 * @return {String} The comparison value
18894 asText : function(s){
18895 return String(s).replace(this.stripTagsRE, "");
18899 * Strips all HTML tags to sort on text only - Case insensitive
18900 * @param {Mixed} s The value being converted
18901 * @return {String} The comparison value
18903 asUCText : function(s){
18904 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18908 * Case insensitive string
18909 * @param {Mixed} s The value being converted
18910 * @return {String} The comparison value
18912 asUCString : function(s) {
18913 return String(s).toUpperCase();
18918 * @param {Mixed} s The value being converted
18919 * @return {Number} The comparison value
18921 asDate : function(s) {
18925 if(s instanceof Date){
18926 return s.getTime();
18928 return Date.parse(String(s));
18933 * @param {Mixed} s The value being converted
18934 * @return {Float} The comparison value
18936 asFloat : function(s) {
18937 var val = parseFloat(String(s).replace(/,/g, ""));
18938 if(isNaN(val)) val = 0;
18944 * @param {Mixed} s The value being converted
18945 * @return {Number} The comparison value
18947 asInt : function(s) {
18948 var val = parseInt(String(s).replace(/,/g, ""));
18949 if(isNaN(val)) val = 0;
18954 * Ext JS Library 1.1.1
18955 * Copyright(c) 2006-2007, Ext JS, LLC.
18957 * Originally Released Under LGPL - original licence link has changed is not relivant.
18960 * <script type="text/javascript">
18964 * @class Roo.data.Record
18965 * Instances of this class encapsulate both record <em>definition</em> information, and record
18966 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18967 * to access Records cached in an {@link Roo.data.Store} object.<br>
18969 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18970 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18973 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18975 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18976 * {@link #create}. The parameters are the same.
18977 * @param {Array} data An associative Array of data values keyed by the field name.
18978 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18979 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18980 * not specified an integer id is generated.
18982 Roo.data.Record = function(data, id){
18983 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18988 * Generate a constructor for a specific record layout.
18989 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18990 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18991 * Each field definition object may contain the following properties: <ul>
18992 * <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,
18993 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18994 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18995 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18996 * is being used, then this is a string containing the javascript expression to reference the data relative to
18997 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18998 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18999 * this may be omitted.</p></li>
19000 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19001 * <ul><li>auto (Default, implies no conversion)</li>
19006 * <li>date</li></ul></p></li>
19007 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19008 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19009 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19010 * by the Reader into an object that will be stored in the Record. It is passed the
19011 * following parameters:<ul>
19012 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19014 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19016 * <br>usage:<br><pre><code>
19017 var TopicRecord = Roo.data.Record.create(
19018 {name: 'title', mapping: 'topic_title'},
19019 {name: 'author', mapping: 'username'},
19020 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19021 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19022 {name: 'lastPoster', mapping: 'user2'},
19023 {name: 'excerpt', mapping: 'post_text'}
19026 var myNewRecord = new TopicRecord({
19027 title: 'Do my job please',
19030 lastPost: new Date(),
19031 lastPoster: 'Animal',
19032 excerpt: 'No way dude!'
19034 myStore.add(myNewRecord);
19039 Roo.data.Record.create = function(o){
19040 var f = function(){
19041 f.superclass.constructor.apply(this, arguments);
19043 Roo.extend(f, Roo.data.Record);
19044 var p = f.prototype;
19045 p.fields = new Roo.util.MixedCollection(false, function(field){
19048 for(var i = 0, len = o.length; i < len; i++){
19049 p.fields.add(new Roo.data.Field(o[i]));
19051 f.getField = function(name){
19052 return p.fields.get(name);
19057 Roo.data.Record.AUTO_ID = 1000;
19058 Roo.data.Record.EDIT = 'edit';
19059 Roo.data.Record.REJECT = 'reject';
19060 Roo.data.Record.COMMIT = 'commit';
19062 Roo.data.Record.prototype = {
19064 * Readonly flag - true if this record has been modified.
19073 join : function(store){
19074 this.store = store;
19078 * Set the named field to the specified value.
19079 * @param {String} name The name of the field to set.
19080 * @param {Object} value The value to set the field to.
19082 set : function(name, value){
19083 if(this.data[name] == value){
19087 if(!this.modified){
19088 this.modified = {};
19090 if(typeof this.modified[name] == 'undefined'){
19091 this.modified[name] = this.data[name];
19093 this.data[name] = value;
19094 if(!this.editing && this.store){
19095 this.store.afterEdit(this);
19100 * Get the value of the named field.
19101 * @param {String} name The name of the field to get the value of.
19102 * @return {Object} The value of the field.
19104 get : function(name){
19105 return this.data[name];
19109 beginEdit : function(){
19110 this.editing = true;
19111 this.modified = {};
19115 cancelEdit : function(){
19116 this.editing = false;
19117 delete this.modified;
19121 endEdit : function(){
19122 this.editing = false;
19123 if(this.dirty && this.store){
19124 this.store.afterEdit(this);
19129 * Usually called by the {@link Roo.data.Store} which owns the Record.
19130 * Rejects all changes made to the Record since either creation, or the last commit operation.
19131 * Modified fields are reverted to their original values.
19133 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19134 * of reject operations.
19136 reject : function(){
19137 var m = this.modified;
19139 if(typeof m[n] != "function"){
19140 this.data[n] = m[n];
19143 this.dirty = false;
19144 delete this.modified;
19145 this.editing = false;
19147 this.store.afterReject(this);
19152 * Usually called by the {@link Roo.data.Store} which owns the Record.
19153 * Commits all changes made to the Record since either creation, or the last commit operation.
19155 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19156 * of commit operations.
19158 commit : function(){
19159 this.dirty = false;
19160 delete this.modified;
19161 this.editing = false;
19163 this.store.afterCommit(this);
19168 hasError : function(){
19169 return this.error != null;
19173 clearError : function(){
19178 * Creates a copy of this record.
19179 * @param {String} id (optional) A new record id if you don't want to use this record's id
19182 copy : function(newId) {
19183 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19187 * Ext JS Library 1.1.1
19188 * Copyright(c) 2006-2007, Ext JS, LLC.
19190 * Originally Released Under LGPL - original licence link has changed is not relivant.
19193 * <script type="text/javascript">
19199 * @class Roo.data.Store
19200 * @extends Roo.util.Observable
19201 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19202 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19204 * 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
19205 * has no knowledge of the format of the data returned by the Proxy.<br>
19207 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19208 * instances from the data object. These records are cached and made available through accessor functions.
19210 * Creates a new Store.
19211 * @param {Object} config A config object containing the objects needed for the Store to access data,
19212 * and read the data into Records.
19214 Roo.data.Store = function(config){
19215 this.data = new Roo.util.MixedCollection(false);
19216 this.data.getKey = function(o){
19219 this.baseParams = {};
19221 this.paramNames = {
19226 "multisort" : "_multisort"
19229 if(config && config.data){
19230 this.inlineData = config.data;
19231 delete config.data;
19234 Roo.apply(this, config);
19236 if(this.reader){ // reader passed
19237 this.reader = Roo.factory(this.reader, Roo.data);
19238 this.reader.xmodule = this.xmodule || false;
19239 if(!this.recordType){
19240 this.recordType = this.reader.recordType;
19242 if(this.reader.onMetaChange){
19243 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19247 if(this.recordType){
19248 this.fields = this.recordType.prototype.fields;
19250 this.modified = [];
19254 * @event datachanged
19255 * Fires when the data cache has changed, and a widget which is using this Store
19256 * as a Record cache should refresh its view.
19257 * @param {Store} this
19259 datachanged : true,
19261 * @event metachange
19262 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19263 * @param {Store} this
19264 * @param {Object} meta The JSON metadata
19269 * Fires when Records have been added to the Store
19270 * @param {Store} this
19271 * @param {Roo.data.Record[]} records The array of Records added
19272 * @param {Number} index The index at which the record(s) were added
19277 * Fires when a Record has been removed from the Store
19278 * @param {Store} this
19279 * @param {Roo.data.Record} record The Record that was removed
19280 * @param {Number} index The index at which the record was removed
19285 * Fires when a Record has been updated
19286 * @param {Store} this
19287 * @param {Roo.data.Record} record The Record that was updated
19288 * @param {String} operation The update operation being performed. Value may be one of:
19290 Roo.data.Record.EDIT
19291 Roo.data.Record.REJECT
19292 Roo.data.Record.COMMIT
19298 * Fires when the data cache has been cleared.
19299 * @param {Store} this
19303 * @event beforeload
19304 * Fires before a request is made for a new data object. If the beforeload handler returns false
19305 * the load action will be canceled.
19306 * @param {Store} this
19307 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19312 * Fires after a new set of Records has been loaded.
19313 * @param {Store} this
19314 * @param {Roo.data.Record[]} records The Records that were loaded
19315 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19319 * @event loadexception
19320 * Fires if an exception occurs in the Proxy during loading.
19321 * Called with the signature of the Proxy's "loadexception" event.
19322 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19325 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19326 * @param {Object} load options
19327 * @param {Object} jsonData from your request (normally this contains the Exception)
19329 loadexception : true
19333 this.proxy = Roo.factory(this.proxy, Roo.data);
19334 this.proxy.xmodule = this.xmodule || false;
19335 this.relayEvents(this.proxy, ["loadexception"]);
19337 this.sortToggle = {};
19338 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19340 Roo.data.Store.superclass.constructor.call(this);
19342 if(this.inlineData){
19343 this.loadData(this.inlineData);
19344 delete this.inlineData;
19347 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19349 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19350 * without a remote query - used by combo/forms at present.
19354 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19357 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19360 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19361 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19364 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19365 * on any HTTP request
19368 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19371 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19375 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19376 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19378 remoteSort : false,
19381 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19382 * loaded or when a record is removed. (defaults to false).
19384 pruneModifiedRecords : false,
19387 lastOptions : null,
19390 * Add Records to the Store and fires the add event.
19391 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19393 add : function(records){
19394 records = [].concat(records);
19395 for(var i = 0, len = records.length; i < len; i++){
19396 records[i].join(this);
19398 var index = this.data.length;
19399 this.data.addAll(records);
19400 this.fireEvent("add", this, records, index);
19404 * Remove a Record from the Store and fires the remove event.
19405 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19407 remove : function(record){
19408 var index = this.data.indexOf(record);
19409 this.data.removeAt(index);
19410 if(this.pruneModifiedRecords){
19411 this.modified.remove(record);
19413 this.fireEvent("remove", this, record, index);
19417 * Remove all Records from the Store and fires the clear event.
19419 removeAll : function(){
19421 if(this.pruneModifiedRecords){
19422 this.modified = [];
19424 this.fireEvent("clear", this);
19428 * Inserts Records to the Store at the given index and fires the add event.
19429 * @param {Number} index The start index at which to insert the passed Records.
19430 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19432 insert : function(index, records){
19433 records = [].concat(records);
19434 for(var i = 0, len = records.length; i < len; i++){
19435 this.data.insert(index, records[i]);
19436 records[i].join(this);
19438 this.fireEvent("add", this, records, index);
19442 * Get the index within the cache of the passed Record.
19443 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19444 * @return {Number} The index of the passed Record. Returns -1 if not found.
19446 indexOf : function(record){
19447 return this.data.indexOf(record);
19451 * Get the index within the cache of the Record with the passed id.
19452 * @param {String} id The id of the Record to find.
19453 * @return {Number} The index of the Record. Returns -1 if not found.
19455 indexOfId : function(id){
19456 return this.data.indexOfKey(id);
19460 * Get the Record with the specified id.
19461 * @param {String} id The id of the Record to find.
19462 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19464 getById : function(id){
19465 return this.data.key(id);
19469 * Get the Record at the specified index.
19470 * @param {Number} index The index of the Record to find.
19471 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19473 getAt : function(index){
19474 return this.data.itemAt(index);
19478 * Returns a range of Records between specified indices.
19479 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19480 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19481 * @return {Roo.data.Record[]} An array of Records
19483 getRange : function(start, end){
19484 return this.data.getRange(start, end);
19488 storeOptions : function(o){
19489 o = Roo.apply({}, o);
19492 this.lastOptions = o;
19496 * Loads the Record cache from the configured Proxy using the configured Reader.
19498 * If using remote paging, then the first load call must specify the <em>start</em>
19499 * and <em>limit</em> properties in the options.params property to establish the initial
19500 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19502 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19503 * and this call will return before the new data has been loaded. Perform any post-processing
19504 * in a callback function, or in a "load" event handler.</strong>
19506 * @param {Object} options An object containing properties which control loading options:<ul>
19507 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19508 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19509 * passed the following arguments:<ul>
19510 * <li>r : Roo.data.Record[]</li>
19511 * <li>options: Options object from the load call</li>
19512 * <li>success: Boolean success indicator</li></ul></li>
19513 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19514 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19517 load : function(options){
19518 options = options || {};
19519 if(this.fireEvent("beforeload", this, options) !== false){
19520 this.storeOptions(options);
19521 var p = Roo.apply(options.params || {}, this.baseParams);
19522 // if meta was not loaded from remote source.. try requesting it.
19523 if (!this.reader.metaFromRemote) {
19524 p._requestMeta = 1;
19526 if(this.sortInfo && this.remoteSort){
19527 var pn = this.paramNames;
19528 p[pn["sort"]] = this.sortInfo.field;
19529 p[pn["dir"]] = this.sortInfo.direction;
19531 if (this.multiSort) {
19532 var pn = this.paramNames;
19533 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19536 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19541 * Reloads the Record cache from the configured Proxy using the configured Reader and
19542 * the options from the last load operation performed.
19543 * @param {Object} options (optional) An object containing properties which may override the options
19544 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19545 * the most recently used options are reused).
19547 reload : function(options){
19548 this.load(Roo.applyIf(options||{}, this.lastOptions));
19552 // Called as a callback by the Reader during a load operation.
19553 loadRecords : function(o, options, success){
19554 if(!o || success === false){
19555 if(success !== false){
19556 this.fireEvent("load", this, [], options);
19558 if(options.callback){
19559 options.callback.call(options.scope || this, [], options, false);
19563 // if data returned failure - throw an exception.
19564 if (o.success === false) {
19565 // show a message if no listener is registered.
19566 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
19567 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
19569 // loadmask wil be hooked into this..
19570 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19573 var r = o.records, t = o.totalRecords || r.length;
19574 if(!options || options.add !== true){
19575 if(this.pruneModifiedRecords){
19576 this.modified = [];
19578 for(var i = 0, len = r.length; i < len; i++){
19582 this.data = this.snapshot;
19583 delete this.snapshot;
19586 this.data.addAll(r);
19587 this.totalLength = t;
19589 this.fireEvent("datachanged", this);
19591 this.totalLength = Math.max(t, this.data.length+r.length);
19594 this.fireEvent("load", this, r, options);
19595 if(options.callback){
19596 options.callback.call(options.scope || this, r, options, true);
19602 * Loads data from a passed data block. A Reader which understands the format of the data
19603 * must have been configured in the constructor.
19604 * @param {Object} data The data block from which to read the Records. The format of the data expected
19605 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19606 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19608 loadData : function(o, append){
19609 var r = this.reader.readRecords(o);
19610 this.loadRecords(r, {add: append}, true);
19614 * Gets the number of cached records.
19616 * <em>If using paging, this may not be the total size of the dataset. If the data object
19617 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19618 * the data set size</em>
19620 getCount : function(){
19621 return this.data.length || 0;
19625 * Gets the total number of records in the dataset as returned by the server.
19627 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19628 * the dataset size</em>
19630 getTotalCount : function(){
19631 return this.totalLength || 0;
19635 * Returns the sort state of the Store as an object with two properties:
19637 field {String} The name of the field by which the Records are sorted
19638 direction {String} The sort order, "ASC" or "DESC"
19641 getSortState : function(){
19642 return this.sortInfo;
19646 applySort : function(){
19647 if(this.sortInfo && !this.remoteSort){
19648 var s = this.sortInfo, f = s.field;
19649 var st = this.fields.get(f).sortType;
19650 var fn = function(r1, r2){
19651 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19652 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19654 this.data.sort(s.direction, fn);
19655 if(this.snapshot && this.snapshot != this.data){
19656 this.snapshot.sort(s.direction, fn);
19662 * Sets the default sort column and order to be used by the next load operation.
19663 * @param {String} fieldName The name of the field to sort by.
19664 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19666 setDefaultSort : function(field, dir){
19667 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19671 * Sort the Records.
19672 * If remote sorting is used, the sort is performed on the server, and the cache is
19673 * reloaded. If local sorting is used, the cache is sorted internally.
19674 * @param {String} fieldName The name of the field to sort by.
19675 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19677 sort : function(fieldName, dir){
19678 var f = this.fields.get(fieldName);
19680 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19682 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19683 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19688 this.sortToggle[f.name] = dir;
19689 this.sortInfo = {field: f.name, direction: dir};
19690 if(!this.remoteSort){
19692 this.fireEvent("datachanged", this);
19694 this.load(this.lastOptions);
19699 * Calls the specified function for each of the Records in the cache.
19700 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19701 * Returning <em>false</em> aborts and exits the iteration.
19702 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19704 each : function(fn, scope){
19705 this.data.each(fn, scope);
19709 * Gets all records modified since the last commit. Modified records are persisted across load operations
19710 * (e.g., during paging).
19711 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19713 getModifiedRecords : function(){
19714 return this.modified;
19718 createFilterFn : function(property, value, anyMatch){
19719 if(!value.exec){ // not a regex
19720 value = String(value);
19721 if(value.length == 0){
19724 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19726 return function(r){
19727 return value.test(r.data[property]);
19732 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19733 * @param {String} property A field on your records
19734 * @param {Number} start The record index to start at (defaults to 0)
19735 * @param {Number} end The last record index to include (defaults to length - 1)
19736 * @return {Number} The sum
19738 sum : function(property, start, end){
19739 var rs = this.data.items, v = 0;
19740 start = start || 0;
19741 end = (end || end === 0) ? end : rs.length-1;
19743 for(var i = start; i <= end; i++){
19744 v += (rs[i].data[property] || 0);
19750 * Filter the records by a specified property.
19751 * @param {String} field A field on your records
19752 * @param {String/RegExp} value Either a string that the field
19753 * should start with or a RegExp to test against the field
19754 * @param {Boolean} anyMatch True to match any part not just the beginning
19756 filter : function(property, value, anyMatch){
19757 var fn = this.createFilterFn(property, value, anyMatch);
19758 return fn ? this.filterBy(fn) : this.clearFilter();
19762 * Filter by a function. The specified function will be called with each
19763 * record in this data source. If the function returns true the record is included,
19764 * otherwise it is filtered.
19765 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19766 * @param {Object} scope (optional) The scope of the function (defaults to this)
19768 filterBy : function(fn, scope){
19769 this.snapshot = this.snapshot || this.data;
19770 this.data = this.queryBy(fn, scope||this);
19771 this.fireEvent("datachanged", this);
19775 * Query the records by a specified property.
19776 * @param {String} field A field on your records
19777 * @param {String/RegExp} value Either a string that the field
19778 * should start with or a RegExp to test against the field
19779 * @param {Boolean} anyMatch True to match any part not just the beginning
19780 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19782 query : function(property, value, anyMatch){
19783 var fn = this.createFilterFn(property, value, anyMatch);
19784 return fn ? this.queryBy(fn) : this.data.clone();
19788 * Query by a function. The specified function will be called with each
19789 * record in this data source. If the function returns true the record is included
19791 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19792 * @param {Object} scope (optional) The scope of the function (defaults to this)
19793 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19795 queryBy : function(fn, scope){
19796 var data = this.snapshot || this.data;
19797 return data.filterBy(fn, scope||this);
19801 * Collects unique values for a particular dataIndex from this store.
19802 * @param {String} dataIndex The property to collect
19803 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19804 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19805 * @return {Array} An array of the unique values
19807 collect : function(dataIndex, allowNull, bypassFilter){
19808 var d = (bypassFilter === true && this.snapshot) ?
19809 this.snapshot.items : this.data.items;
19810 var v, sv, r = [], l = {};
19811 for(var i = 0, len = d.length; i < len; i++){
19812 v = d[i].data[dataIndex];
19814 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19823 * Revert to a view of the Record cache with no filtering applied.
19824 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19826 clearFilter : function(suppressEvent){
19827 if(this.snapshot && this.snapshot != this.data){
19828 this.data = this.snapshot;
19829 delete this.snapshot;
19830 if(suppressEvent !== true){
19831 this.fireEvent("datachanged", this);
19837 afterEdit : function(record){
19838 if(this.modified.indexOf(record) == -1){
19839 this.modified.push(record);
19841 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19845 afterReject : function(record){
19846 this.modified.remove(record);
19847 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19851 afterCommit : function(record){
19852 this.modified.remove(record);
19853 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19857 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19858 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19860 commitChanges : function(){
19861 var m = this.modified.slice(0);
19862 this.modified = [];
19863 for(var i = 0, len = m.length; i < len; i++){
19869 * Cancel outstanding changes on all changed records.
19871 rejectChanges : function(){
19872 var m = this.modified.slice(0);
19873 this.modified = [];
19874 for(var i = 0, len = m.length; i < len; i++){
19879 onMetaChange : function(meta, rtype, o){
19880 this.recordType = rtype;
19881 this.fields = rtype.prototype.fields;
19882 delete this.snapshot;
19883 this.sortInfo = meta.sortInfo || this.sortInfo;
19884 this.modified = [];
19885 this.fireEvent('metachange', this, this.reader.meta);
19889 * Ext JS Library 1.1.1
19890 * Copyright(c) 2006-2007, Ext JS, LLC.
19892 * Originally Released Under LGPL - original licence link has changed is not relivant.
19895 * <script type="text/javascript">
19899 * @class Roo.data.SimpleStore
19900 * @extends Roo.data.Store
19901 * Small helper class to make creating Stores from Array data easier.
19902 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19903 * @cfg {Array} fields An array of field definition objects, or field name strings.
19904 * @cfg {Array} data The multi-dimensional array of data
19906 * @param {Object} config
19908 Roo.data.SimpleStore = function(config){
19909 Roo.data.SimpleStore.superclass.constructor.call(this, {
19911 reader: new Roo.data.ArrayReader({
19914 Roo.data.Record.create(config.fields)
19916 proxy : new Roo.data.MemoryProxy(config.data)
19920 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19922 * Ext JS Library 1.1.1
19923 * Copyright(c) 2006-2007, Ext JS, LLC.
19925 * Originally Released Under LGPL - original licence link has changed is not relivant.
19928 * <script type="text/javascript">
19933 * @extends Roo.data.Store
19934 * @class Roo.data.JsonStore
19935 * Small helper class to make creating Stores for JSON data easier. <br/>
19937 var store = new Roo.data.JsonStore({
19938 url: 'get-images.php',
19940 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19943 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19944 * JsonReader and HttpProxy (unless inline data is provided).</b>
19945 * @cfg {Array} fields An array of field definition objects, or field name strings.
19947 * @param {Object} config
19949 Roo.data.JsonStore = function(c){
19950 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19951 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19952 reader: new Roo.data.JsonReader(c, c.fields)
19955 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19957 * Ext JS Library 1.1.1
19958 * Copyright(c) 2006-2007, Ext JS, LLC.
19960 * Originally Released Under LGPL - original licence link has changed is not relivant.
19963 * <script type="text/javascript">
19967 Roo.data.Field = function(config){
19968 if(typeof config == "string"){
19969 config = {name: config};
19971 Roo.apply(this, config);
19974 this.type = "auto";
19977 var st = Roo.data.SortTypes;
19978 // named sortTypes are supported, here we look them up
19979 if(typeof this.sortType == "string"){
19980 this.sortType = st[this.sortType];
19983 // set default sortType for strings and dates
19984 if(!this.sortType){
19987 this.sortType = st.asUCString;
19990 this.sortType = st.asDate;
19993 this.sortType = st.none;
19998 var stripRe = /[\$,%]/g;
20000 // prebuilt conversion function for this field, instead of
20001 // switching every time we're reading a value
20003 var cv, dateFormat = this.dateFormat;
20008 cv = function(v){ return v; };
20011 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20015 return v !== undefined && v !== null && v !== '' ?
20016 parseInt(String(v).replace(stripRe, ""), 10) : '';
20021 return v !== undefined && v !== null && v !== '' ?
20022 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20027 cv = function(v){ return v === true || v === "true" || v == 1; };
20034 if(v instanceof Date){
20038 if(dateFormat == "timestamp"){
20039 return new Date(v*1000);
20041 return Date.parseDate(v, dateFormat);
20043 var parsed = Date.parse(v);
20044 return parsed ? new Date(parsed) : null;
20053 Roo.data.Field.prototype = {
20061 * Ext JS Library 1.1.1
20062 * Copyright(c) 2006-2007, Ext JS, LLC.
20064 * Originally Released Under LGPL - original licence link has changed is not relivant.
20067 * <script type="text/javascript">
20070 // Base class for reading structured data from a data source. This class is intended to be
20071 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20074 * @class Roo.data.DataReader
20075 * Base class for reading structured data from a data source. This class is intended to be
20076 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20079 Roo.data.DataReader = function(meta, recordType){
20083 this.recordType = recordType instanceof Array ?
20084 Roo.data.Record.create(recordType) : recordType;
20087 Roo.data.DataReader.prototype = {
20089 * Create an empty record
20090 * @param {Object} data (optional) - overlay some values
20091 * @return {Roo.data.Record} record created.
20093 newRow : function(d) {
20095 this.recordType.prototype.fields.each(function(c) {
20097 case 'int' : da[c.name] = 0; break;
20098 case 'date' : da[c.name] = new Date(); break;
20099 case 'float' : da[c.name] = 0.0; break;
20100 case 'boolean' : da[c.name] = false; break;
20101 default : da[c.name] = ""; break;
20105 return new this.recordType(Roo.apply(da, d));
20110 * Ext JS Library 1.1.1
20111 * Copyright(c) 2006-2007, Ext JS, LLC.
20113 * Originally Released Under LGPL - original licence link has changed is not relivant.
20116 * <script type="text/javascript">
20120 * @class Roo.data.DataProxy
20121 * @extends Roo.data.Observable
20122 * This class is an abstract base class for implementations which provide retrieval of
20123 * unformatted data objects.<br>
20125 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20126 * (of the appropriate type which knows how to parse the data object) to provide a block of
20127 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20129 * Custom implementations must implement the load method as described in
20130 * {@link Roo.data.HttpProxy#load}.
20132 Roo.data.DataProxy = function(){
20135 * @event beforeload
20136 * Fires before a network request is made to retrieve a data object.
20137 * @param {Object} This DataProxy object.
20138 * @param {Object} params The params parameter to the load function.
20143 * Fires before the load method's callback is called.
20144 * @param {Object} This DataProxy object.
20145 * @param {Object} o The data object.
20146 * @param {Object} arg The callback argument object passed to the load function.
20150 * @event loadexception
20151 * Fires if an Exception occurs during data retrieval.
20152 * @param {Object} This DataProxy object.
20153 * @param {Object} o The data object.
20154 * @param {Object} arg The callback argument object passed to the load function.
20155 * @param {Object} e The Exception.
20157 loadexception : true
20159 Roo.data.DataProxy.superclass.constructor.call(this);
20162 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20165 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20169 * Ext JS Library 1.1.1
20170 * Copyright(c) 2006-2007, Ext JS, LLC.
20172 * Originally Released Under LGPL - original licence link has changed is not relivant.
20175 * <script type="text/javascript">
20178 * @class Roo.data.MemoryProxy
20179 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20180 * to the Reader when its load method is called.
20182 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20184 Roo.data.MemoryProxy = function(data){
20188 Roo.data.MemoryProxy.superclass.constructor.call(this);
20192 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20194 * Load data from the requested source (in this case an in-memory
20195 * data object passed to the constructor), read the data object into
20196 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20197 * process that block using the passed callback.
20198 * @param {Object} params This parameter is not used by the MemoryProxy class.
20199 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20200 * object into a block of Roo.data.Records.
20201 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20202 * The function must be passed <ul>
20203 * <li>The Record block object</li>
20204 * <li>The "arg" argument from the load function</li>
20205 * <li>A boolean success indicator</li>
20207 * @param {Object} scope The scope in which to call the callback
20208 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20210 load : function(params, reader, callback, scope, arg){
20211 params = params || {};
20214 result = reader.readRecords(this.data);
20216 this.fireEvent("loadexception", this, arg, null, e);
20217 callback.call(scope, null, arg, false);
20220 callback.call(scope, result, arg, true);
20224 update : function(params, records){
20229 * Ext JS Library 1.1.1
20230 * Copyright(c) 2006-2007, Ext JS, LLC.
20232 * Originally Released Under LGPL - original licence link has changed is not relivant.
20235 * <script type="text/javascript">
20238 * @class Roo.data.HttpProxy
20239 * @extends Roo.data.DataProxy
20240 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20241 * configured to reference a certain URL.<br><br>
20243 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20244 * from which the running page was served.<br><br>
20246 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20248 * Be aware that to enable the browser to parse an XML document, the server must set
20249 * the Content-Type header in the HTTP response to "text/xml".
20251 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20252 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20253 * will be used to make the request.
20255 Roo.data.HttpProxy = function(conn){
20256 Roo.data.HttpProxy.superclass.constructor.call(this);
20257 // is conn a conn config or a real conn?
20259 this.useAjax = !conn || !conn.events;
20263 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20264 // thse are take from connection...
20267 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20270 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20271 * extra parameters to each request made by this object. (defaults to undefined)
20274 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20275 * to each request made by this object. (defaults to undefined)
20278 * @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)
20281 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20284 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20290 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20294 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20295 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20296 * a finer-grained basis than the DataProxy events.
20298 getConnection : function(){
20299 return this.useAjax ? Roo.Ajax : this.conn;
20303 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20304 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20305 * process that block using the passed callback.
20306 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20307 * for the request to the remote server.
20308 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20309 * object into a block of Roo.data.Records.
20310 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20311 * The function must be passed <ul>
20312 * <li>The Record block object</li>
20313 * <li>The "arg" argument from the load function</li>
20314 * <li>A boolean success indicator</li>
20316 * @param {Object} scope The scope in which to call the callback
20317 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20319 load : function(params, reader, callback, scope, arg){
20320 if(this.fireEvent("beforeload", this, params) !== false){
20322 params : params || {},
20324 callback : callback,
20329 callback : this.loadResponse,
20333 Roo.applyIf(o, this.conn);
20334 if(this.activeRequest){
20335 Roo.Ajax.abort(this.activeRequest);
20337 this.activeRequest = Roo.Ajax.request(o);
20339 this.conn.request(o);
20342 callback.call(scope||this, null, arg, false);
20347 loadResponse : function(o, success, response){
20348 delete this.activeRequest;
20350 this.fireEvent("loadexception", this, o, response);
20351 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20356 result = o.reader.read(response);
20358 this.fireEvent("loadexception", this, o, response, e);
20359 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20363 this.fireEvent("load", this, o, o.request.arg);
20364 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20368 update : function(dataSet){
20373 updateResponse : function(dataSet){
20378 * Ext JS Library 1.1.1
20379 * Copyright(c) 2006-2007, Ext JS, LLC.
20381 * Originally Released Under LGPL - original licence link has changed is not relivant.
20384 * <script type="text/javascript">
20388 * @class Roo.data.ScriptTagProxy
20389 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20390 * other than the originating domain of the running page.<br><br>
20392 * <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
20393 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20395 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20396 * source code that is used as the source inside a <script> tag.<br><br>
20398 * In order for the browser to process the returned data, the server must wrap the data object
20399 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20400 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20401 * depending on whether the callback name was passed:
20404 boolean scriptTag = false;
20405 String cb = request.getParameter("callback");
20408 response.setContentType("text/javascript");
20410 response.setContentType("application/x-json");
20412 Writer out = response.getWriter();
20414 out.write(cb + "(");
20416 out.print(dataBlock.toJsonString());
20423 * @param {Object} config A configuration object.
20425 Roo.data.ScriptTagProxy = function(config){
20426 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20427 Roo.apply(this, config);
20428 this.head = document.getElementsByTagName("head")[0];
20431 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20433 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20435 * @cfg {String} url The URL from which to request the data object.
20438 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20442 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20443 * the server the name of the callback function set up by the load call to process the returned data object.
20444 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20445 * javascript output which calls this named function passing the data object as its only parameter.
20447 callbackParam : "callback",
20449 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20450 * name to the request.
20455 * Load data from the configured URL, read the data object into
20456 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20457 * process that block using the passed callback.
20458 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20459 * for the request to the remote server.
20460 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20461 * object into a block of Roo.data.Records.
20462 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20463 * The function must be passed <ul>
20464 * <li>The Record block object</li>
20465 * <li>The "arg" argument from the load function</li>
20466 * <li>A boolean success indicator</li>
20468 * @param {Object} scope The scope in which to call the callback
20469 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20471 load : function(params, reader, callback, scope, arg){
20472 if(this.fireEvent("beforeload", this, params) !== false){
20474 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20476 var url = this.url;
20477 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20479 url += "&_dc=" + (new Date().getTime());
20481 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20484 cb : "stcCallback"+transId,
20485 scriptId : "stcScript"+transId,
20489 callback : callback,
20495 window[trans.cb] = function(o){
20496 conn.handleResponse(o, trans);
20499 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20501 if(this.autoAbort !== false){
20505 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20507 var script = document.createElement("script");
20508 script.setAttribute("src", url);
20509 script.setAttribute("type", "text/javascript");
20510 script.setAttribute("id", trans.scriptId);
20511 this.head.appendChild(script);
20513 this.trans = trans;
20515 callback.call(scope||this, null, arg, false);
20520 isLoading : function(){
20521 return this.trans ? true : false;
20525 * Abort the current server request.
20527 abort : function(){
20528 if(this.isLoading()){
20529 this.destroyTrans(this.trans);
20534 destroyTrans : function(trans, isLoaded){
20535 this.head.removeChild(document.getElementById(trans.scriptId));
20536 clearTimeout(trans.timeoutId);
20538 window[trans.cb] = undefined;
20540 delete window[trans.cb];
20543 // if hasn't been loaded, wait for load to remove it to prevent script error
20544 window[trans.cb] = function(){
20545 window[trans.cb] = undefined;
20547 delete window[trans.cb];
20554 handleResponse : function(o, trans){
20555 this.trans = false;
20556 this.destroyTrans(trans, true);
20559 result = trans.reader.readRecords(o);
20561 this.fireEvent("loadexception", this, o, trans.arg, e);
20562 trans.callback.call(trans.scope||window, null, trans.arg, false);
20565 this.fireEvent("load", this, o, trans.arg);
20566 trans.callback.call(trans.scope||window, result, trans.arg, true);
20570 handleFailure : function(trans){
20571 this.trans = false;
20572 this.destroyTrans(trans, false);
20573 this.fireEvent("loadexception", this, null, trans.arg);
20574 trans.callback.call(trans.scope||window, null, trans.arg, false);
20578 * Ext JS Library 1.1.1
20579 * Copyright(c) 2006-2007, Ext JS, LLC.
20581 * Originally Released Under LGPL - original licence link has changed is not relivant.
20584 * <script type="text/javascript">
20588 * @class Roo.data.JsonReader
20589 * @extends Roo.data.DataReader
20590 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20591 * based on mappings in a provided Roo.data.Record constructor.
20593 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20594 * in the reply previously.
20599 var RecordDef = Roo.data.Record.create([
20600 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20601 {name: 'occupation'} // This field will use "occupation" as the mapping.
20603 var myReader = new Roo.data.JsonReader({
20604 totalProperty: "results", // The property which contains the total dataset size (optional)
20605 root: "rows", // The property which contains an Array of row objects
20606 id: "id" // The property within each row object that provides an ID for the record (optional)
20610 * This would consume a JSON file like this:
20612 { 'results': 2, 'rows': [
20613 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20614 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20617 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20618 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20619 * paged from the remote server.
20620 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20621 * @cfg {String} root name of the property which contains the Array of row objects.
20622 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20624 * Create a new JsonReader
20625 * @param {Object} meta Metadata configuration options
20626 * @param {Object} recordType Either an Array of field definition objects,
20627 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20629 Roo.data.JsonReader = function(meta, recordType){
20632 // set some defaults:
20633 Roo.applyIf(meta, {
20634 totalProperty: 'total',
20635 successProperty : 'success',
20640 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20642 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20645 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20646 * Used by Store query builder to append _requestMeta to params.
20649 metaFromRemote : false,
20651 * This method is only used by a DataProxy which has retrieved data from a remote server.
20652 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20653 * @return {Object} data A data block which is used by an Roo.data.Store object as
20654 * a cache of Roo.data.Records.
20656 read : function(response){
20657 var json = response.responseText;
20659 var o = /* eval:var:o */ eval("("+json+")");
20661 throw {message: "JsonReader.read: Json object not found"};
20667 this.metaFromRemote = true;
20668 this.meta = o.metaData;
20669 this.recordType = Roo.data.Record.create(o.metaData.fields);
20670 this.onMetaChange(this.meta, this.recordType, o);
20672 return this.readRecords(o);
20675 // private function a store will implement
20676 onMetaChange : function(meta, recordType, o){
20683 simpleAccess: function(obj, subsc) {
20690 getJsonAccessor: function(){
20692 return function(expr) {
20694 return(re.test(expr))
20695 ? new Function("obj", "return obj." + expr)
20700 return Roo.emptyFn;
20705 * Create a data block containing Roo.data.Records from an XML document.
20706 * @param {Object} o An object which contains an Array of row objects in the property specified
20707 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20708 * which contains the total size of the dataset.
20709 * @return {Object} data A data block which is used by an Roo.data.Store object as
20710 * a cache of Roo.data.Records.
20712 readRecords : function(o){
20714 * After any data loads, the raw JSON data is available for further custom processing.
20718 var s = this.meta, Record = this.recordType,
20719 f = Record.prototype.fields, fi = f.items, fl = f.length;
20721 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20723 if(s.totalProperty) {
20724 this.getTotal = this.getJsonAccessor(s.totalProperty);
20726 if(s.successProperty) {
20727 this.getSuccess = this.getJsonAccessor(s.successProperty);
20729 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20731 var g = this.getJsonAccessor(s.id);
20732 this.getId = function(rec) {
20734 return (r === undefined || r === "") ? null : r;
20737 this.getId = function(){return null;};
20740 for(var jj = 0; jj < fl; jj++){
20742 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20743 this.ef[jj] = this.getJsonAccessor(map);
20747 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20748 if(s.totalProperty){
20749 var vt = parseInt(this.getTotal(o), 10);
20754 if(s.successProperty){
20755 var vs = this.getSuccess(o);
20756 if(vs === false || vs === 'false'){
20761 for(var i = 0; i < c; i++){
20764 var id = this.getId(n);
20765 for(var j = 0; j < fl; j++){
20767 var v = this.ef[j](n);
20769 Roo.log('missing convert for ' + f.name);
20773 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20775 var record = new Record(values, id);
20777 records[i] = record;
20782 totalRecords : totalRecords
20787 * Ext JS Library 1.1.1
20788 * Copyright(c) 2006-2007, Ext JS, LLC.
20790 * Originally Released Under LGPL - original licence link has changed is not relivant.
20793 * <script type="text/javascript">
20797 * @class Roo.data.XmlReader
20798 * @extends Roo.data.DataReader
20799 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20800 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20802 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20803 * header in the HTTP response must be set to "text/xml".</em>
20807 var RecordDef = Roo.data.Record.create([
20808 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20809 {name: 'occupation'} // This field will use "occupation" as the mapping.
20811 var myReader = new Roo.data.XmlReader({
20812 totalRecords: "results", // The element which contains the total dataset size (optional)
20813 record: "row", // The repeated element which contains row information
20814 id: "id" // The element within the row that provides an ID for the record (optional)
20818 * This would consume an XML file like this:
20822 <results>2</results>
20825 <name>Bill</name>
20826 <occupation>Gardener</occupation>
20830 <name>Ben</name>
20831 <occupation>Horticulturalist</occupation>
20835 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20836 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20837 * paged from the remote server.
20838 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20839 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20840 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20841 * a record identifier value.
20843 * Create a new XmlReader
20844 * @param {Object} meta Metadata configuration options
20845 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20846 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20847 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20849 Roo.data.XmlReader = function(meta, recordType){
20851 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20853 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20855 * This method is only used by a DataProxy which has retrieved data from a remote server.
20856 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20857 * to contain a method called 'responseXML' that returns an XML document object.
20858 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20859 * a cache of Roo.data.Records.
20861 read : function(response){
20862 var doc = response.responseXML;
20864 throw {message: "XmlReader.read: XML Document not available"};
20866 return this.readRecords(doc);
20870 * Create a data block containing Roo.data.Records from an XML document.
20871 * @param {Object} doc A parsed XML document.
20872 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20873 * a cache of Roo.data.Records.
20875 readRecords : function(doc){
20877 * After any data loads/reads, the raw XML Document is available for further custom processing.
20878 * @type XMLDocument
20880 this.xmlData = doc;
20881 var root = doc.documentElement || doc;
20882 var q = Roo.DomQuery;
20883 var recordType = this.recordType, fields = recordType.prototype.fields;
20884 var sid = this.meta.id;
20885 var totalRecords = 0, success = true;
20886 if(this.meta.totalRecords){
20887 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20890 if(this.meta.success){
20891 var sv = q.selectValue(this.meta.success, root, true);
20892 success = sv !== false && sv !== 'false';
20895 var ns = q.select(this.meta.record, root);
20896 for(var i = 0, len = ns.length; i < len; i++) {
20899 var id = sid ? q.selectValue(sid, n) : undefined;
20900 for(var j = 0, jlen = fields.length; j < jlen; j++){
20901 var f = fields.items[j];
20902 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20904 values[f.name] = v;
20906 var record = new recordType(values, id);
20908 records[records.length] = record;
20914 totalRecords : totalRecords || records.length
20919 * Ext JS Library 1.1.1
20920 * Copyright(c) 2006-2007, Ext JS, LLC.
20922 * Originally Released Under LGPL - original licence link has changed is not relivant.
20925 * <script type="text/javascript">
20929 * @class Roo.data.ArrayReader
20930 * @extends Roo.data.DataReader
20931 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20932 * Each element of that Array represents a row of data fields. The
20933 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20934 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20938 var RecordDef = Roo.data.Record.create([
20939 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20940 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20942 var myReader = new Roo.data.ArrayReader({
20943 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20947 * This would consume an Array like this:
20949 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20951 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20953 * Create a new JsonReader
20954 * @param {Object} meta Metadata configuration options.
20955 * @param {Object} recordType Either an Array of field definition objects
20956 * as specified to {@link Roo.data.Record#create},
20957 * or an {@link Roo.data.Record} object
20958 * created using {@link Roo.data.Record#create}.
20960 Roo.data.ArrayReader = function(meta, recordType){
20961 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20964 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20966 * Create a data block containing Roo.data.Records from an XML document.
20967 * @param {Object} o An Array of row objects which represents the dataset.
20968 * @return {Object} data A data block which is used by an Roo.data.Store object as
20969 * a cache of Roo.data.Records.
20971 readRecords : function(o){
20972 var sid = this.meta ? this.meta.id : null;
20973 var recordType = this.recordType, fields = recordType.prototype.fields;
20976 for(var i = 0; i < root.length; i++){
20979 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20980 for(var j = 0, jlen = fields.length; j < jlen; j++){
20981 var f = fields.items[j];
20982 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20983 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20985 values[f.name] = v;
20987 var record = new recordType(values, id);
20989 records[records.length] = record;
20993 totalRecords : records.length
20998 * Ext JS Library 1.1.1
20999 * Copyright(c) 2006-2007, Ext JS, LLC.
21001 * Originally Released Under LGPL - original licence link has changed is not relivant.
21004 * <script type="text/javascript">
21009 * @class Roo.data.Tree
21010 * @extends Roo.util.Observable
21011 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21012 * in the tree have most standard DOM functionality.
21014 * @param {Node} root (optional) The root node
21016 Roo.data.Tree = function(root){
21017 this.nodeHash = {};
21019 * The root node for this tree
21024 this.setRootNode(root);
21029 * Fires when a new child node is appended to a node in this tree.
21030 * @param {Tree} tree The owner tree
21031 * @param {Node} parent The parent node
21032 * @param {Node} node The newly appended node
21033 * @param {Number} index The index of the newly appended node
21038 * Fires when a child node is removed from a node in this tree.
21039 * @param {Tree} tree The owner tree
21040 * @param {Node} parent The parent node
21041 * @param {Node} node The child node removed
21046 * Fires when a node is moved to a new location in the tree
21047 * @param {Tree} tree The owner tree
21048 * @param {Node} node The node moved
21049 * @param {Node} oldParent The old parent of this node
21050 * @param {Node} newParent The new parent of this node
21051 * @param {Number} index The index it was moved to
21056 * Fires when a new child node is inserted in a node in this tree.
21057 * @param {Tree} tree The owner tree
21058 * @param {Node} parent The parent node
21059 * @param {Node} node The child node inserted
21060 * @param {Node} refNode The child node the node was inserted before
21064 * @event beforeappend
21065 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21066 * @param {Tree} tree The owner tree
21067 * @param {Node} parent The parent node
21068 * @param {Node} node The child node to be appended
21070 "beforeappend" : true,
21072 * @event beforeremove
21073 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21074 * @param {Tree} tree The owner tree
21075 * @param {Node} parent The parent node
21076 * @param {Node} node The child node to be removed
21078 "beforeremove" : true,
21080 * @event beforemove
21081 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21082 * @param {Tree} tree The owner tree
21083 * @param {Node} node The node being moved
21084 * @param {Node} oldParent The parent of the node
21085 * @param {Node} newParent The new parent the node is moving to
21086 * @param {Number} index The index it is being moved to
21088 "beforemove" : true,
21090 * @event beforeinsert
21091 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21092 * @param {Tree} tree The owner tree
21093 * @param {Node} parent The parent node
21094 * @param {Node} node The child node to be inserted
21095 * @param {Node} refNode The child node the node is being inserted before
21097 "beforeinsert" : true
21100 Roo.data.Tree.superclass.constructor.call(this);
21103 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21104 pathSeparator: "/",
21106 proxyNodeEvent : function(){
21107 return this.fireEvent.apply(this, arguments);
21111 * Returns the root node for this tree.
21114 getRootNode : function(){
21119 * Sets the root node for this tree.
21120 * @param {Node} node
21123 setRootNode : function(node){
21125 node.ownerTree = this;
21126 node.isRoot = true;
21127 this.registerNode(node);
21132 * Gets a node in this tree by its id.
21133 * @param {String} id
21136 getNodeById : function(id){
21137 return this.nodeHash[id];
21140 registerNode : function(node){
21141 this.nodeHash[node.id] = node;
21144 unregisterNode : function(node){
21145 delete this.nodeHash[node.id];
21148 toString : function(){
21149 return "[Tree"+(this.id?" "+this.id:"")+"]";
21154 * @class Roo.data.Node
21155 * @extends Roo.util.Observable
21156 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21157 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21159 * @param {Object} attributes The attributes/config for the node
21161 Roo.data.Node = function(attributes){
21163 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21166 this.attributes = attributes || {};
21167 this.leaf = this.attributes.leaf;
21169 * The node id. @type String
21171 this.id = this.attributes.id;
21173 this.id = Roo.id(null, "ynode-");
21174 this.attributes.id = this.id;
21177 * All child nodes of this node. @type Array
21179 this.childNodes = [];
21180 if(!this.childNodes.indexOf){ // indexOf is a must
21181 this.childNodes.indexOf = function(o){
21182 for(var i = 0, len = this.length; i < len; i++){
21191 * The parent node for this node. @type Node
21193 this.parentNode = null;
21195 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21197 this.firstChild = null;
21199 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21201 this.lastChild = null;
21203 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21205 this.previousSibling = null;
21207 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21209 this.nextSibling = null;
21214 * Fires when a new child node is appended
21215 * @param {Tree} tree The owner tree
21216 * @param {Node} this This node
21217 * @param {Node} node The newly appended node
21218 * @param {Number} index The index of the newly appended node
21223 * Fires when a child node is removed
21224 * @param {Tree} tree The owner tree
21225 * @param {Node} this This node
21226 * @param {Node} node The removed node
21231 * Fires when this node is moved to a new location in the tree
21232 * @param {Tree} tree The owner tree
21233 * @param {Node} this This node
21234 * @param {Node} oldParent The old parent of this node
21235 * @param {Node} newParent The new parent of this node
21236 * @param {Number} index The index it was moved to
21241 * Fires when a new child node is inserted.
21242 * @param {Tree} tree The owner tree
21243 * @param {Node} this This node
21244 * @param {Node} node The child node inserted
21245 * @param {Node} refNode The child node the node was inserted before
21249 * @event beforeappend
21250 * Fires before a new child is appended, return false to cancel the append.
21251 * @param {Tree} tree The owner tree
21252 * @param {Node} this This node
21253 * @param {Node} node The child node to be appended
21255 "beforeappend" : true,
21257 * @event beforeremove
21258 * Fires before a child is removed, return false to cancel the remove.
21259 * @param {Tree} tree The owner tree
21260 * @param {Node} this This node
21261 * @param {Node} node The child node to be removed
21263 "beforeremove" : true,
21265 * @event beforemove
21266 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21267 * @param {Tree} tree The owner tree
21268 * @param {Node} this This node
21269 * @param {Node} oldParent The parent of this node
21270 * @param {Node} newParent The new parent this node is moving to
21271 * @param {Number} index The index it is being moved to
21273 "beforemove" : true,
21275 * @event beforeinsert
21276 * Fires before a new child is inserted, return false to cancel the insert.
21277 * @param {Tree} tree The owner tree
21278 * @param {Node} this This node
21279 * @param {Node} node The child node to be inserted
21280 * @param {Node} refNode The child node the node is being inserted before
21282 "beforeinsert" : true
21284 this.listeners = this.attributes.listeners;
21285 Roo.data.Node.superclass.constructor.call(this);
21288 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21289 fireEvent : function(evtName){
21290 // first do standard event for this node
21291 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21294 // then bubble it up to the tree if the event wasn't cancelled
21295 var ot = this.getOwnerTree();
21297 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21305 * Returns true if this node is a leaf
21306 * @return {Boolean}
21308 isLeaf : function(){
21309 return this.leaf === true;
21313 setFirstChild : function(node){
21314 this.firstChild = node;
21318 setLastChild : function(node){
21319 this.lastChild = node;
21324 * Returns true if this node is the last child of its parent
21325 * @return {Boolean}
21327 isLast : function(){
21328 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21332 * Returns true if this node is the first child of its parent
21333 * @return {Boolean}
21335 isFirst : function(){
21336 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21339 hasChildNodes : function(){
21340 return !this.isLeaf() && this.childNodes.length > 0;
21344 * Insert node(s) as the last child node of this node.
21345 * @param {Node/Array} node The node or Array of nodes to append
21346 * @return {Node} The appended node if single append, or null if an array was passed
21348 appendChild : function(node){
21350 if(node instanceof Array){
21352 }else if(arguments.length > 1){
21355 // if passed an array or multiple args do them one by one
21357 for(var i = 0, len = multi.length; i < len; i++) {
21358 this.appendChild(multi[i]);
21361 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21364 var index = this.childNodes.length;
21365 var oldParent = node.parentNode;
21366 // it's a move, make sure we move it cleanly
21368 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21371 oldParent.removeChild(node);
21373 index = this.childNodes.length;
21375 this.setFirstChild(node);
21377 this.childNodes.push(node);
21378 node.parentNode = this;
21379 var ps = this.childNodes[index-1];
21381 node.previousSibling = ps;
21382 ps.nextSibling = node;
21384 node.previousSibling = null;
21386 node.nextSibling = null;
21387 this.setLastChild(node);
21388 node.setOwnerTree(this.getOwnerTree());
21389 this.fireEvent("append", this.ownerTree, this, node, index);
21391 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21398 * Removes a child node from this node.
21399 * @param {Node} node The node to remove
21400 * @return {Node} The removed node
21402 removeChild : function(node){
21403 var index = this.childNodes.indexOf(node);
21407 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21411 // remove it from childNodes collection
21412 this.childNodes.splice(index, 1);
21415 if(node.previousSibling){
21416 node.previousSibling.nextSibling = node.nextSibling;
21418 if(node.nextSibling){
21419 node.nextSibling.previousSibling = node.previousSibling;
21422 // update child refs
21423 if(this.firstChild == node){
21424 this.setFirstChild(node.nextSibling);
21426 if(this.lastChild == node){
21427 this.setLastChild(node.previousSibling);
21430 node.setOwnerTree(null);
21431 // clear any references from the node
21432 node.parentNode = null;
21433 node.previousSibling = null;
21434 node.nextSibling = null;
21435 this.fireEvent("remove", this.ownerTree, this, node);
21440 * Inserts the first node before the second node in this nodes childNodes collection.
21441 * @param {Node} node The node to insert
21442 * @param {Node} refNode The node to insert before (if null the node is appended)
21443 * @return {Node} The inserted node
21445 insertBefore : function(node, refNode){
21446 if(!refNode){ // like standard Dom, refNode can be null for append
21447 return this.appendChild(node);
21450 if(node == refNode){
21454 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21457 var index = this.childNodes.indexOf(refNode);
21458 var oldParent = node.parentNode;
21459 var refIndex = index;
21461 // when moving internally, indexes will change after remove
21462 if(oldParent == this && this.childNodes.indexOf(node) < index){
21466 // it's a move, make sure we move it cleanly
21468 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21471 oldParent.removeChild(node);
21474 this.setFirstChild(node);
21476 this.childNodes.splice(refIndex, 0, node);
21477 node.parentNode = this;
21478 var ps = this.childNodes[refIndex-1];
21480 node.previousSibling = ps;
21481 ps.nextSibling = node;
21483 node.previousSibling = null;
21485 node.nextSibling = refNode;
21486 refNode.previousSibling = node;
21487 node.setOwnerTree(this.getOwnerTree());
21488 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21490 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21496 * Returns the child node at the specified index.
21497 * @param {Number} index
21500 item : function(index){
21501 return this.childNodes[index];
21505 * Replaces one child node in this node with another.
21506 * @param {Node} newChild The replacement node
21507 * @param {Node} oldChild The node to replace
21508 * @return {Node} The replaced node
21510 replaceChild : function(newChild, oldChild){
21511 this.insertBefore(newChild, oldChild);
21512 this.removeChild(oldChild);
21517 * Returns the index of a child node
21518 * @param {Node} node
21519 * @return {Number} The index of the node or -1 if it was not found
21521 indexOf : function(child){
21522 return this.childNodes.indexOf(child);
21526 * Returns the tree this node is in.
21529 getOwnerTree : function(){
21530 // if it doesn't have one, look for one
21531 if(!this.ownerTree){
21535 this.ownerTree = p.ownerTree;
21541 return this.ownerTree;
21545 * Returns depth of this node (the root node has a depth of 0)
21548 getDepth : function(){
21551 while(p.parentNode){
21559 setOwnerTree : function(tree){
21560 // if it's move, we need to update everyone
21561 if(tree != this.ownerTree){
21562 if(this.ownerTree){
21563 this.ownerTree.unregisterNode(this);
21565 this.ownerTree = tree;
21566 var cs = this.childNodes;
21567 for(var i = 0, len = cs.length; i < len; i++) {
21568 cs[i].setOwnerTree(tree);
21571 tree.registerNode(this);
21577 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21578 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21579 * @return {String} The path
21581 getPath : function(attr){
21582 attr = attr || "id";
21583 var p = this.parentNode;
21584 var b = [this.attributes[attr]];
21586 b.unshift(p.attributes[attr]);
21589 var sep = this.getOwnerTree().pathSeparator;
21590 return sep + b.join(sep);
21594 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21595 * function call will be the scope provided or the current node. The arguments to the function
21596 * will be the args provided or the current node. If the function returns false at any point,
21597 * the bubble is stopped.
21598 * @param {Function} fn The function to call
21599 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21600 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21602 bubble : function(fn, scope, args){
21605 if(fn.call(scope || p, args || p) === false){
21613 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21614 * function call will be the scope provided or the current node. The arguments to the function
21615 * will be the args provided or the current node. If the function returns false at any point,
21616 * the cascade is stopped on that branch.
21617 * @param {Function} fn The function to call
21618 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21619 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21621 cascade : function(fn, scope, args){
21622 if(fn.call(scope || this, args || this) !== false){
21623 var cs = this.childNodes;
21624 for(var i = 0, len = cs.length; i < len; i++) {
21625 cs[i].cascade(fn, scope, args);
21631 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21632 * function call will be the scope provided or the current node. The arguments to the function
21633 * will be the args provided or the current node. If the function returns false at any point,
21634 * the iteration stops.
21635 * @param {Function} fn The function to call
21636 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21637 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21639 eachChild : function(fn, scope, args){
21640 var cs = this.childNodes;
21641 for(var i = 0, len = cs.length; i < len; i++) {
21642 if(fn.call(scope || this, args || cs[i]) === false){
21649 * Finds the first child that has the attribute with the specified value.
21650 * @param {String} attribute The attribute name
21651 * @param {Mixed} value The value to search for
21652 * @return {Node} The found child or null if none was found
21654 findChild : function(attribute, value){
21655 var cs = this.childNodes;
21656 for(var i = 0, len = cs.length; i < len; i++) {
21657 if(cs[i].attributes[attribute] == value){
21665 * Finds the first child by a custom function. The child matches if the function passed
21667 * @param {Function} fn
21668 * @param {Object} scope (optional)
21669 * @return {Node} The found child or null if none was found
21671 findChildBy : function(fn, scope){
21672 var cs = this.childNodes;
21673 for(var i = 0, len = cs.length; i < len; i++) {
21674 if(fn.call(scope||cs[i], cs[i]) === true){
21682 * Sorts this nodes children using the supplied sort function
21683 * @param {Function} fn
21684 * @param {Object} scope (optional)
21686 sort : function(fn, scope){
21687 var cs = this.childNodes;
21688 var len = cs.length;
21690 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21692 for(var i = 0; i < len; i++){
21694 n.previousSibling = cs[i-1];
21695 n.nextSibling = cs[i+1];
21697 this.setFirstChild(n);
21700 this.setLastChild(n);
21707 * Returns true if this node is an ancestor (at any point) of the passed node.
21708 * @param {Node} node
21709 * @return {Boolean}
21711 contains : function(node){
21712 return node.isAncestor(this);
21716 * Returns true if the passed node is an ancestor (at any point) of this node.
21717 * @param {Node} node
21718 * @return {Boolean}
21720 isAncestor : function(node){
21721 var p = this.parentNode;
21731 toString : function(){
21732 return "[Node"+(this.id?" "+this.id:"")+"]";
21736 * Ext JS Library 1.1.1
21737 * Copyright(c) 2006-2007, Ext JS, LLC.
21739 * Originally Released Under LGPL - original licence link has changed is not relivant.
21742 * <script type="text/javascript">
21747 * @class Roo.ComponentMgr
21748 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21751 Roo.ComponentMgr = function(){
21752 var all = new Roo.util.MixedCollection();
21756 * Registers a component.
21757 * @param {Roo.Component} c The component
21759 register : function(c){
21764 * Unregisters a component.
21765 * @param {Roo.Component} c The component
21767 unregister : function(c){
21772 * Returns a component by id
21773 * @param {String} id The component id
21775 get : function(id){
21776 return all.get(id);
21780 * Registers a function that will be called when a specified component is added to ComponentMgr
21781 * @param {String} id The component id
21782 * @param {Funtction} fn The callback function
21783 * @param {Object} scope The scope of the callback
21785 onAvailable : function(id, fn, scope){
21786 all.on("add", function(index, o){
21788 fn.call(scope || o, o);
21789 all.un("add", fn, scope);
21796 * Ext JS Library 1.1.1
21797 * Copyright(c) 2006-2007, Ext JS, LLC.
21799 * Originally Released Under LGPL - original licence link has changed is not relivant.
21802 * <script type="text/javascript">
21806 * @class Roo.Component
21807 * @extends Roo.util.Observable
21808 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21809 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21810 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21811 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21812 * All visual components (widgets) that require rendering into a layout should subclass Component.
21814 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21815 * 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
21816 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21818 Roo.Component = function(config){
21819 config = config || {};
21820 if(config.tagName || config.dom || typeof config == "string"){ // element object
21821 config = {el: config, id: config.id || config};
21823 this.initialConfig = config;
21825 Roo.apply(this, config);
21829 * Fires after the component is disabled.
21830 * @param {Roo.Component} this
21835 * Fires after the component is enabled.
21836 * @param {Roo.Component} this
21840 * @event beforeshow
21841 * Fires before the component is shown. Return false to stop the show.
21842 * @param {Roo.Component} this
21847 * Fires after the component is shown.
21848 * @param {Roo.Component} this
21852 * @event beforehide
21853 * Fires before the component is hidden. Return false to stop the hide.
21854 * @param {Roo.Component} this
21859 * Fires after the component is hidden.
21860 * @param {Roo.Component} this
21864 * @event beforerender
21865 * Fires before the component is rendered. Return false to stop the render.
21866 * @param {Roo.Component} this
21868 beforerender : true,
21871 * Fires after the component is rendered.
21872 * @param {Roo.Component} this
21876 * @event beforedestroy
21877 * Fires before the component is destroyed. Return false to stop the destroy.
21878 * @param {Roo.Component} this
21880 beforedestroy : true,
21883 * Fires after the component is destroyed.
21884 * @param {Roo.Component} this
21889 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21891 Roo.ComponentMgr.register(this);
21892 Roo.Component.superclass.constructor.call(this);
21893 this.initComponent();
21894 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21895 this.render(this.renderTo);
21896 delete this.renderTo;
21901 Roo.Component.AUTO_ID = 1000;
21903 Roo.extend(Roo.Component, Roo.util.Observable, {
21905 * @scope Roo.Component.prototype
21907 * true if this component is hidden. Read-only.
21912 * true if this component is disabled. Read-only.
21917 * true if this component has been rendered. Read-only.
21921 /** @cfg {String} disableClass
21922 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21924 disabledClass : "x-item-disabled",
21925 /** @cfg {Boolean} allowDomMove
21926 * Whether the component can move the Dom node when rendering (defaults to true).
21928 allowDomMove : true,
21929 /** @cfg {String} hideMode
21930 * How this component should hidden. Supported values are
21931 * "visibility" (css visibility), "offsets" (negative offset position) and
21932 * "display" (css display) - defaults to "display".
21934 hideMode: 'display',
21937 ctype : "Roo.Component",
21940 * @cfg {String} actionMode
21941 * which property holds the element that used for hide() / show() / disable() / enable()
21947 getActionEl : function(){
21948 return this[this.actionMode];
21951 initComponent : Roo.emptyFn,
21953 * If this is a lazy rendering component, render it to its container element.
21954 * @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.
21956 render : function(container, position){
21957 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21958 if(!container && this.el){
21959 this.el = Roo.get(this.el);
21960 container = this.el.dom.parentNode;
21961 this.allowDomMove = false;
21963 this.container = Roo.get(container);
21964 this.rendered = true;
21965 if(position !== undefined){
21966 if(typeof position == 'number'){
21967 position = this.container.dom.childNodes[position];
21969 position = Roo.getDom(position);
21972 this.onRender(this.container, position || null);
21974 this.el.addClass(this.cls);
21978 this.el.applyStyles(this.style);
21981 this.fireEvent("render", this);
21982 this.afterRender(this.container);
21994 // default function is not really useful
21995 onRender : function(ct, position){
21997 this.el = Roo.get(this.el);
21998 if(this.allowDomMove !== false){
21999 ct.dom.insertBefore(this.el.dom, position);
22005 getAutoCreate : function(){
22006 var cfg = typeof this.autoCreate == "object" ?
22007 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22008 if(this.id && !cfg.id){
22015 afterRender : Roo.emptyFn,
22018 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22019 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22021 destroy : function(){
22022 if(this.fireEvent("beforedestroy", this) !== false){
22023 this.purgeListeners();
22024 this.beforeDestroy();
22026 this.el.removeAllListeners();
22028 if(this.actionMode == "container"){
22029 this.container.remove();
22033 Roo.ComponentMgr.unregister(this);
22034 this.fireEvent("destroy", this);
22039 beforeDestroy : function(){
22044 onDestroy : function(){
22049 * Returns the underlying {@link Roo.Element}.
22050 * @return {Roo.Element} The element
22052 getEl : function(){
22057 * Returns the id of this component.
22060 getId : function(){
22065 * Try to focus this component.
22066 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22067 * @return {Roo.Component} this
22069 focus : function(selectText){
22072 if(selectText === true){
22073 this.el.dom.select();
22088 * Disable this component.
22089 * @return {Roo.Component} this
22091 disable : function(){
22095 this.disabled = true;
22096 this.fireEvent("disable", this);
22101 onDisable : function(){
22102 this.getActionEl().addClass(this.disabledClass);
22103 this.el.dom.disabled = true;
22107 * Enable this component.
22108 * @return {Roo.Component} this
22110 enable : function(){
22114 this.disabled = false;
22115 this.fireEvent("enable", this);
22120 onEnable : function(){
22121 this.getActionEl().removeClass(this.disabledClass);
22122 this.el.dom.disabled = false;
22126 * Convenience function for setting disabled/enabled by boolean.
22127 * @param {Boolean} disabled
22129 setDisabled : function(disabled){
22130 this[disabled ? "disable" : "enable"]();
22134 * Show this component.
22135 * @return {Roo.Component} this
22138 if(this.fireEvent("beforeshow", this) !== false){
22139 this.hidden = false;
22143 this.fireEvent("show", this);
22149 onShow : function(){
22150 var ae = this.getActionEl();
22151 if(this.hideMode == 'visibility'){
22152 ae.dom.style.visibility = "visible";
22153 }else if(this.hideMode == 'offsets'){
22154 ae.removeClass('x-hidden');
22156 ae.dom.style.display = "";
22161 * Hide this component.
22162 * @return {Roo.Component} this
22165 if(this.fireEvent("beforehide", this) !== false){
22166 this.hidden = true;
22170 this.fireEvent("hide", this);
22176 onHide : function(){
22177 var ae = this.getActionEl();
22178 if(this.hideMode == 'visibility'){
22179 ae.dom.style.visibility = "hidden";
22180 }else if(this.hideMode == 'offsets'){
22181 ae.addClass('x-hidden');
22183 ae.dom.style.display = "none";
22188 * Convenience function to hide or show this component by boolean.
22189 * @param {Boolean} visible True to show, false to hide
22190 * @return {Roo.Component} this
22192 setVisible: function(visible){
22202 * Returns true if this component is visible.
22204 isVisible : function(){
22205 return this.getActionEl().isVisible();
22208 cloneConfig : function(overrides){
22209 overrides = overrides || {};
22210 var id = overrides.id || Roo.id();
22211 var cfg = Roo.applyIf(overrides, this.initialConfig);
22212 cfg.id = id; // prevent dup id
22213 return new this.constructor(cfg);
22217 * Ext JS Library 1.1.1
22218 * Copyright(c) 2006-2007, Ext JS, LLC.
22220 * Originally Released Under LGPL - original licence link has changed is not relivant.
22223 * <script type="text/javascript">
22228 * @extends Roo.Element
22229 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22230 * automatic maintaining of shadow/shim positions.
22231 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22232 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22233 * you can pass a string with a CSS class name. False turns off the shadow.
22234 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22235 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22236 * @cfg {String} cls CSS class to add to the element
22237 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22238 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22240 * @param {Object} config An object with config options.
22241 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22244 Roo.Layer = function(config, existingEl){
22245 config = config || {};
22246 var dh = Roo.DomHelper;
22247 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22249 this.dom = Roo.getDom(existingEl);
22252 var o = config.dh || {tag: "div", cls: "x-layer"};
22253 this.dom = dh.append(pel, o);
22256 this.addClass(config.cls);
22258 this.constrain = config.constrain !== false;
22259 this.visibilityMode = Roo.Element.VISIBILITY;
22261 this.id = this.dom.id = config.id;
22263 this.id = Roo.id(this.dom);
22265 this.zindex = config.zindex || this.getZIndex();
22266 this.position("absolute", this.zindex);
22268 this.shadowOffset = config.shadowOffset || 4;
22269 this.shadow = new Roo.Shadow({
22270 offset : this.shadowOffset,
22271 mode : config.shadow
22274 this.shadowOffset = 0;
22276 this.useShim = config.shim !== false && Roo.useShims;
22277 this.useDisplay = config.useDisplay;
22281 var supr = Roo.Element.prototype;
22283 // shims are shared among layer to keep from having 100 iframes
22286 Roo.extend(Roo.Layer, Roo.Element, {
22288 getZIndex : function(){
22289 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22292 getShim : function(){
22299 var shim = shims.shift();
22301 shim = this.createShim();
22302 shim.enableDisplayMode('block');
22303 shim.dom.style.display = 'none';
22304 shim.dom.style.visibility = 'visible';
22306 var pn = this.dom.parentNode;
22307 if(shim.dom.parentNode != pn){
22308 pn.insertBefore(shim.dom, this.dom);
22310 shim.setStyle('z-index', this.getZIndex()-2);
22315 hideShim : function(){
22317 this.shim.setDisplayed(false);
22318 shims.push(this.shim);
22323 disableShadow : function(){
22325 this.shadowDisabled = true;
22326 this.shadow.hide();
22327 this.lastShadowOffset = this.shadowOffset;
22328 this.shadowOffset = 0;
22332 enableShadow : function(show){
22334 this.shadowDisabled = false;
22335 this.shadowOffset = this.lastShadowOffset;
22336 delete this.lastShadowOffset;
22344 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22345 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22346 sync : function(doShow){
22347 var sw = this.shadow;
22348 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22349 var sh = this.getShim();
22351 var w = this.getWidth(),
22352 h = this.getHeight();
22354 var l = this.getLeft(true),
22355 t = this.getTop(true);
22357 if(sw && !this.shadowDisabled){
22358 if(doShow && !sw.isVisible()){
22361 sw.realign(l, t, w, h);
22367 // fit the shim behind the shadow, so it is shimmed too
22368 var a = sw.adjusts, s = sh.dom.style;
22369 s.left = (Math.min(l, l+a.l))+"px";
22370 s.top = (Math.min(t, t+a.t))+"px";
22371 s.width = (w+a.w)+"px";
22372 s.height = (h+a.h)+"px";
22379 sh.setLeftTop(l, t);
22386 destroy : function(){
22389 this.shadow.hide();
22391 this.removeAllListeners();
22392 var pn = this.dom.parentNode;
22394 pn.removeChild(this.dom);
22396 Roo.Element.uncache(this.id);
22399 remove : function(){
22404 beginUpdate : function(){
22405 this.updating = true;
22409 endUpdate : function(){
22410 this.updating = false;
22415 hideUnders : function(negOffset){
22417 this.shadow.hide();
22423 constrainXY : function(){
22424 if(this.constrain){
22425 var vw = Roo.lib.Dom.getViewWidth(),
22426 vh = Roo.lib.Dom.getViewHeight();
22427 var s = Roo.get(document).getScroll();
22429 var xy = this.getXY();
22430 var x = xy[0], y = xy[1];
22431 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22432 // only move it if it needs it
22434 // first validate right/bottom
22435 if((x + w) > vw+s.left){
22436 x = vw - w - this.shadowOffset;
22439 if((y + h) > vh+s.top){
22440 y = vh - h - this.shadowOffset;
22443 // then make sure top/left isn't negative
22454 var ay = this.avoidY;
22455 if(y <= ay && (y+h) >= ay){
22461 supr.setXY.call(this, xy);
22467 isVisible : function(){
22468 return this.visible;
22472 showAction : function(){
22473 this.visible = true; // track visibility to prevent getStyle calls
22474 if(this.useDisplay === true){
22475 this.setDisplayed("");
22476 }else if(this.lastXY){
22477 supr.setXY.call(this, this.lastXY);
22478 }else if(this.lastLT){
22479 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22484 hideAction : function(){
22485 this.visible = false;
22486 if(this.useDisplay === true){
22487 this.setDisplayed(false);
22489 this.setLeftTop(-10000,-10000);
22493 // overridden Element method
22494 setVisible : function(v, a, d, c, e){
22499 var cb = function(){
22504 }.createDelegate(this);
22505 supr.setVisible.call(this, true, true, d, cb, e);
22508 this.hideUnders(true);
22517 }.createDelegate(this);
22519 supr.setVisible.call(this, v, a, d, cb, e);
22528 storeXY : function(xy){
22529 delete this.lastLT;
22533 storeLeftTop : function(left, top){
22534 delete this.lastXY;
22535 this.lastLT = [left, top];
22539 beforeFx : function(){
22540 this.beforeAction();
22541 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22545 afterFx : function(){
22546 Roo.Layer.superclass.afterFx.apply(this, arguments);
22547 this.sync(this.isVisible());
22551 beforeAction : function(){
22552 if(!this.updating && this.shadow){
22553 this.shadow.hide();
22557 // overridden Element method
22558 setLeft : function(left){
22559 this.storeLeftTop(left, this.getTop(true));
22560 supr.setLeft.apply(this, arguments);
22564 setTop : function(top){
22565 this.storeLeftTop(this.getLeft(true), top);
22566 supr.setTop.apply(this, arguments);
22570 setLeftTop : function(left, top){
22571 this.storeLeftTop(left, top);
22572 supr.setLeftTop.apply(this, arguments);
22576 setXY : function(xy, a, d, c, e){
22578 this.beforeAction();
22580 var cb = this.createCB(c);
22581 supr.setXY.call(this, xy, a, d, cb, e);
22588 createCB : function(c){
22599 // overridden Element method
22600 setX : function(x, a, d, c, e){
22601 this.setXY([x, this.getY()], a, d, c, e);
22604 // overridden Element method
22605 setY : function(y, a, d, c, e){
22606 this.setXY([this.getX(), y], a, d, c, e);
22609 // overridden Element method
22610 setSize : function(w, h, a, d, c, e){
22611 this.beforeAction();
22612 var cb = this.createCB(c);
22613 supr.setSize.call(this, w, h, a, d, cb, e);
22619 // overridden Element method
22620 setWidth : function(w, a, d, c, e){
22621 this.beforeAction();
22622 var cb = this.createCB(c);
22623 supr.setWidth.call(this, w, a, d, cb, e);
22629 // overridden Element method
22630 setHeight : function(h, a, d, c, e){
22631 this.beforeAction();
22632 var cb = this.createCB(c);
22633 supr.setHeight.call(this, h, a, d, cb, e);
22639 // overridden Element method
22640 setBounds : function(x, y, w, h, a, d, c, e){
22641 this.beforeAction();
22642 var cb = this.createCB(c);
22644 this.storeXY([x, y]);
22645 supr.setXY.call(this, [x, y]);
22646 supr.setSize.call(this, w, h, a, d, cb, e);
22649 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22655 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22656 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22657 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22658 * @param {Number} zindex The new z-index to set
22659 * @return {this} The Layer
22661 setZIndex : function(zindex){
22662 this.zindex = zindex;
22663 this.setStyle("z-index", zindex + 2);
22665 this.shadow.setZIndex(zindex + 1);
22668 this.shim.setStyle("z-index", zindex);
22674 * Ext JS Library 1.1.1
22675 * Copyright(c) 2006-2007, Ext JS, LLC.
22677 * Originally Released Under LGPL - original licence link has changed is not relivant.
22680 * <script type="text/javascript">
22685 * @class Roo.Shadow
22686 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22687 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22688 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22690 * Create a new Shadow
22691 * @param {Object} config The config object
22693 Roo.Shadow = function(config){
22694 Roo.apply(this, config);
22695 if(typeof this.mode != "string"){
22696 this.mode = this.defaultMode;
22698 var o = this.offset, a = {h: 0};
22699 var rad = Math.floor(this.offset/2);
22700 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22706 a.l -= this.offset + rad;
22707 a.t -= this.offset + rad;
22718 a.l -= (this.offset - rad);
22719 a.t -= this.offset + rad;
22721 a.w -= (this.offset - rad)*2;
22732 a.l -= (this.offset - rad);
22733 a.t -= (this.offset - rad);
22735 a.w -= (this.offset + rad + 1);
22736 a.h -= (this.offset + rad);
22745 Roo.Shadow.prototype = {
22747 * @cfg {String} mode
22748 * The shadow display mode. Supports the following options:<br />
22749 * sides: Shadow displays on both sides and bottom only<br />
22750 * frame: Shadow displays equally on all four sides<br />
22751 * drop: Traditional bottom-right drop shadow (default)
22754 * @cfg {String} offset
22755 * The number of pixels to offset the shadow from the element (defaults to 4)
22760 defaultMode: "drop",
22763 * Displays the shadow under the target element
22764 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22766 show : function(target){
22767 target = Roo.get(target);
22769 this.el = Roo.Shadow.Pool.pull();
22770 if(this.el.dom.nextSibling != target.dom){
22771 this.el.insertBefore(target);
22774 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22776 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22779 target.getLeft(true),
22780 target.getTop(true),
22784 this.el.dom.style.display = "block";
22788 * Returns true if the shadow is visible, else false
22790 isVisible : function(){
22791 return this.el ? true : false;
22795 * Direct alignment when values are already available. Show must be called at least once before
22796 * calling this method to ensure it is initialized.
22797 * @param {Number} left The target element left position
22798 * @param {Number} top The target element top position
22799 * @param {Number} width The target element width
22800 * @param {Number} height The target element height
22802 realign : function(l, t, w, h){
22806 var a = this.adjusts, d = this.el.dom, s = d.style;
22808 s.left = (l+a.l)+"px";
22809 s.top = (t+a.t)+"px";
22810 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22812 if(s.width != sws || s.height != shs){
22816 var cn = d.childNodes;
22817 var sww = Math.max(0, (sw-12))+"px";
22818 cn[0].childNodes[1].style.width = sww;
22819 cn[1].childNodes[1].style.width = sww;
22820 cn[2].childNodes[1].style.width = sww;
22821 cn[1].style.height = Math.max(0, (sh-12))+"px";
22827 * Hides this shadow
22831 this.el.dom.style.display = "none";
22832 Roo.Shadow.Pool.push(this.el);
22838 * Adjust the z-index of this shadow
22839 * @param {Number} zindex The new z-index
22841 setZIndex : function(z){
22844 this.el.setStyle("z-index", z);
22849 // Private utility class that manages the internal Shadow cache
22850 Roo.Shadow.Pool = function(){
22852 var markup = Roo.isIE ?
22853 '<div class="x-ie-shadow"></div>' :
22854 '<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>';
22857 var sh = p.shift();
22859 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22860 sh.autoBoxAdjust = false;
22865 push : function(sh){
22871 * Ext JS Library 1.1.1
22872 * Copyright(c) 2006-2007, Ext JS, LLC.
22874 * Originally Released Under LGPL - original licence link has changed is not relivant.
22877 * <script type="text/javascript">
22881 * @class Roo.BoxComponent
22882 * @extends Roo.Component
22883 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22884 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22885 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22886 * layout containers.
22888 * @param {Roo.Element/String/Object} config The configuration options.
22890 Roo.BoxComponent = function(config){
22891 Roo.Component.call(this, config);
22895 * Fires after the component is resized.
22896 * @param {Roo.Component} this
22897 * @param {Number} adjWidth The box-adjusted width that was set
22898 * @param {Number} adjHeight The box-adjusted height that was set
22899 * @param {Number} rawWidth The width that was originally specified
22900 * @param {Number} rawHeight The height that was originally specified
22905 * Fires after the component is moved.
22906 * @param {Roo.Component} this
22907 * @param {Number} x The new x position
22908 * @param {Number} y The new y position
22914 Roo.extend(Roo.BoxComponent, Roo.Component, {
22915 // private, set in afterRender to signify that the component has been rendered
22917 // private, used to defer height settings to subclasses
22918 deferHeight: false,
22919 /** @cfg {Number} width
22920 * width (optional) size of component
22922 /** @cfg {Number} height
22923 * height (optional) size of component
22927 * Sets the width and height of the component. This method fires the resize event. This method can accept
22928 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22929 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22930 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22931 * @return {Roo.BoxComponent} this
22933 setSize : function(w, h){
22934 // support for standard size objects
22935 if(typeof w == 'object'){
22940 if(!this.boxReady){
22946 // prevent recalcs when not needed
22947 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22950 this.lastSize = {width: w, height: h};
22952 var adj = this.adjustSize(w, h);
22953 var aw = adj.width, ah = adj.height;
22954 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22955 var rz = this.getResizeEl();
22956 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22957 rz.setSize(aw, ah);
22958 }else if(!this.deferHeight && ah !== undefined){
22960 }else if(aw !== undefined){
22963 this.onResize(aw, ah, w, h);
22964 this.fireEvent('resize', this, aw, ah, w, h);
22970 * Gets the current size of the component's underlying element.
22971 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22973 getSize : function(){
22974 return this.el.getSize();
22978 * Gets the current XY position of the component's underlying element.
22979 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22980 * @return {Array} The XY position of the element (e.g., [100, 200])
22982 getPosition : function(local){
22983 if(local === true){
22984 return [this.el.getLeft(true), this.el.getTop(true)];
22986 return this.xy || this.el.getXY();
22990 * Gets the current box measurements of the component's underlying element.
22991 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22992 * @returns {Object} box An object in the format {x, y, width, height}
22994 getBox : function(local){
22995 var s = this.el.getSize();
22997 s.x = this.el.getLeft(true);
22998 s.y = this.el.getTop(true);
23000 var xy = this.xy || this.el.getXY();
23008 * Sets the current box measurements of the component's underlying element.
23009 * @param {Object} box An object in the format {x, y, width, height}
23010 * @returns {Roo.BoxComponent} this
23012 updateBox : function(box){
23013 this.setSize(box.width, box.height);
23014 this.setPagePosition(box.x, box.y);
23019 getResizeEl : function(){
23020 return this.resizeEl || this.el;
23024 getPositionEl : function(){
23025 return this.positionEl || this.el;
23029 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23030 * This method fires the move event.
23031 * @param {Number} left The new left
23032 * @param {Number} top The new top
23033 * @returns {Roo.BoxComponent} this
23035 setPosition : function(x, y){
23038 if(!this.boxReady){
23041 var adj = this.adjustPosition(x, y);
23042 var ax = adj.x, ay = adj.y;
23044 var el = this.getPositionEl();
23045 if(ax !== undefined || ay !== undefined){
23046 if(ax !== undefined && ay !== undefined){
23047 el.setLeftTop(ax, ay);
23048 }else if(ax !== undefined){
23050 }else if(ay !== undefined){
23053 this.onPosition(ax, ay);
23054 this.fireEvent('move', this, ax, ay);
23060 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23061 * This method fires the move event.
23062 * @param {Number} x The new x position
23063 * @param {Number} y The new y position
23064 * @returns {Roo.BoxComponent} this
23066 setPagePosition : function(x, y){
23069 if(!this.boxReady){
23072 if(x === undefined || y === undefined){ // cannot translate undefined points
23075 var p = this.el.translatePoints(x, y);
23076 this.setPosition(p.left, p.top);
23081 onRender : function(ct, position){
23082 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23084 this.resizeEl = Roo.get(this.resizeEl);
23086 if(this.positionEl){
23087 this.positionEl = Roo.get(this.positionEl);
23092 afterRender : function(){
23093 Roo.BoxComponent.superclass.afterRender.call(this);
23094 this.boxReady = true;
23095 this.setSize(this.width, this.height);
23096 if(this.x || this.y){
23097 this.setPosition(this.x, this.y);
23099 if(this.pageX || this.pageY){
23100 this.setPagePosition(this.pageX, this.pageY);
23105 * Force the component's size to recalculate based on the underlying element's current height and width.
23106 * @returns {Roo.BoxComponent} this
23108 syncSize : function(){
23109 delete this.lastSize;
23110 this.setSize(this.el.getWidth(), this.el.getHeight());
23115 * Called after the component is resized, this method is empty by default but can be implemented by any
23116 * subclass that needs to perform custom logic after a resize occurs.
23117 * @param {Number} adjWidth The box-adjusted width that was set
23118 * @param {Number} adjHeight The box-adjusted height that was set
23119 * @param {Number} rawWidth The width that was originally specified
23120 * @param {Number} rawHeight The height that was originally specified
23122 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23127 * Called after the component is moved, this method is empty by default but can be implemented by any
23128 * subclass that needs to perform custom logic after a move occurs.
23129 * @param {Number} x The new x position
23130 * @param {Number} y The new y position
23132 onPosition : function(x, y){
23137 adjustSize : function(w, h){
23138 if(this.autoWidth){
23141 if(this.autoHeight){
23144 return {width : w, height: h};
23148 adjustPosition : function(x, y){
23149 return {x : x, y: y};
23153 * Ext JS Library 1.1.1
23154 * Copyright(c) 2006-2007, Ext JS, LLC.
23156 * Originally Released Under LGPL - original licence link has changed is not relivant.
23159 * <script type="text/javascript">
23164 * @class Roo.SplitBar
23165 * @extends Roo.util.Observable
23166 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23170 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23171 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23172 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23173 split.minSize = 100;
23174 split.maxSize = 600;
23175 split.animate = true;
23176 split.on('moved', splitterMoved);
23179 * Create a new SplitBar
23180 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23181 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23182 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23183 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23184 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23185 position of the SplitBar).
23187 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23190 this.el = Roo.get(dragElement, true);
23191 this.el.dom.unselectable = "on";
23193 this.resizingEl = Roo.get(resizingElement, true);
23197 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23198 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23201 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23204 * The minimum size of the resizing element. (Defaults to 0)
23210 * The maximum size of the resizing element. (Defaults to 2000)
23213 this.maxSize = 2000;
23216 * Whether to animate the transition to the new size
23219 this.animate = false;
23222 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23225 this.useShim = false;
23230 if(!existingProxy){
23232 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23234 this.proxy = Roo.get(existingProxy).dom;
23237 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23240 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23243 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23246 this.dragSpecs = {};
23249 * @private The adapter to use to positon and resize elements
23251 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23252 this.adapter.init(this);
23254 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23256 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23257 this.el.addClass("x-splitbar-h");
23260 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23261 this.el.addClass("x-splitbar-v");
23267 * Fires when the splitter is moved (alias for {@link #event-moved})
23268 * @param {Roo.SplitBar} this
23269 * @param {Number} newSize the new width or height
23274 * Fires when the splitter is moved
23275 * @param {Roo.SplitBar} this
23276 * @param {Number} newSize the new width or height
23280 * @event beforeresize
23281 * Fires before the splitter is dragged
23282 * @param {Roo.SplitBar} this
23284 "beforeresize" : true,
23286 "beforeapply" : true
23289 Roo.util.Observable.call(this);
23292 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23293 onStartProxyDrag : function(x, y){
23294 this.fireEvent("beforeresize", this);
23296 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23298 o.enableDisplayMode("block");
23299 // all splitbars share the same overlay
23300 Roo.SplitBar.prototype.overlay = o;
23302 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23303 this.overlay.show();
23304 Roo.get(this.proxy).setDisplayed("block");
23305 var size = this.adapter.getElementSize(this);
23306 this.activeMinSize = this.getMinimumSize();;
23307 this.activeMaxSize = this.getMaximumSize();;
23308 var c1 = size - this.activeMinSize;
23309 var c2 = Math.max(this.activeMaxSize - size, 0);
23310 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23311 this.dd.resetConstraints();
23312 this.dd.setXConstraint(
23313 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23314 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23316 this.dd.setYConstraint(0, 0);
23318 this.dd.resetConstraints();
23319 this.dd.setXConstraint(0, 0);
23320 this.dd.setYConstraint(
23321 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23322 this.placement == Roo.SplitBar.TOP ? c2 : c1
23325 this.dragSpecs.startSize = size;
23326 this.dragSpecs.startPoint = [x, y];
23327 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23331 * @private Called after the drag operation by the DDProxy
23333 onEndProxyDrag : function(e){
23334 Roo.get(this.proxy).setDisplayed(false);
23335 var endPoint = Roo.lib.Event.getXY(e);
23337 this.overlay.hide();
23340 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23341 newSize = this.dragSpecs.startSize +
23342 (this.placement == Roo.SplitBar.LEFT ?
23343 endPoint[0] - this.dragSpecs.startPoint[0] :
23344 this.dragSpecs.startPoint[0] - endPoint[0]
23347 newSize = this.dragSpecs.startSize +
23348 (this.placement == Roo.SplitBar.TOP ?
23349 endPoint[1] - this.dragSpecs.startPoint[1] :
23350 this.dragSpecs.startPoint[1] - endPoint[1]
23353 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23354 if(newSize != this.dragSpecs.startSize){
23355 if(this.fireEvent('beforeapply', this, newSize) !== false){
23356 this.adapter.setElementSize(this, newSize);
23357 this.fireEvent("moved", this, newSize);
23358 this.fireEvent("resize", this, newSize);
23364 * Get the adapter this SplitBar uses
23365 * @return The adapter object
23367 getAdapter : function(){
23368 return this.adapter;
23372 * Set the adapter this SplitBar uses
23373 * @param {Object} adapter A SplitBar adapter object
23375 setAdapter : function(adapter){
23376 this.adapter = adapter;
23377 this.adapter.init(this);
23381 * Gets the minimum size for the resizing element
23382 * @return {Number} The minimum size
23384 getMinimumSize : function(){
23385 return this.minSize;
23389 * Sets the minimum size for the resizing element
23390 * @param {Number} minSize The minimum size
23392 setMinimumSize : function(minSize){
23393 this.minSize = minSize;
23397 * Gets the maximum size for the resizing element
23398 * @return {Number} The maximum size
23400 getMaximumSize : function(){
23401 return this.maxSize;
23405 * Sets the maximum size for the resizing element
23406 * @param {Number} maxSize The maximum size
23408 setMaximumSize : function(maxSize){
23409 this.maxSize = maxSize;
23413 * Sets the initialize size for the resizing element
23414 * @param {Number} size The initial size
23416 setCurrentSize : function(size){
23417 var oldAnimate = this.animate;
23418 this.animate = false;
23419 this.adapter.setElementSize(this, size);
23420 this.animate = oldAnimate;
23424 * Destroy this splitbar.
23425 * @param {Boolean} removeEl True to remove the element
23427 destroy : function(removeEl){
23429 this.shim.remove();
23432 this.proxy.parentNode.removeChild(this.proxy);
23440 * @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.
23442 Roo.SplitBar.createProxy = function(dir){
23443 var proxy = new Roo.Element(document.createElement("div"));
23444 proxy.unselectable();
23445 var cls = 'x-splitbar-proxy';
23446 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23447 document.body.appendChild(proxy.dom);
23452 * @class Roo.SplitBar.BasicLayoutAdapter
23453 * Default Adapter. It assumes the splitter and resizing element are not positioned
23454 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23456 Roo.SplitBar.BasicLayoutAdapter = function(){
23459 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23460 // do nothing for now
23461 init : function(s){
23465 * Called before drag operations to get the current size of the resizing element.
23466 * @param {Roo.SplitBar} s The SplitBar using this adapter
23468 getElementSize : function(s){
23469 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23470 return s.resizingEl.getWidth();
23472 return s.resizingEl.getHeight();
23477 * Called after drag operations to set the size of the resizing element.
23478 * @param {Roo.SplitBar} s The SplitBar using this adapter
23479 * @param {Number} newSize The new size to set
23480 * @param {Function} onComplete A function to be invoked when resizing is complete
23482 setElementSize : function(s, newSize, onComplete){
23483 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23485 s.resizingEl.setWidth(newSize);
23487 onComplete(s, newSize);
23490 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23495 s.resizingEl.setHeight(newSize);
23497 onComplete(s, newSize);
23500 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23507 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23508 * @extends Roo.SplitBar.BasicLayoutAdapter
23509 * Adapter that moves the splitter element to align with the resized sizing element.
23510 * Used with an absolute positioned SplitBar.
23511 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23512 * document.body, make sure you assign an id to the body element.
23514 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23515 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23516 this.container = Roo.get(container);
23519 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23520 init : function(s){
23521 this.basic.init(s);
23524 getElementSize : function(s){
23525 return this.basic.getElementSize(s);
23528 setElementSize : function(s, newSize, onComplete){
23529 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23532 moveSplitter : function(s){
23533 var yes = Roo.SplitBar;
23534 switch(s.placement){
23536 s.el.setX(s.resizingEl.getRight());
23539 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23542 s.el.setY(s.resizingEl.getBottom());
23545 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23552 * Orientation constant - Create a vertical SplitBar
23556 Roo.SplitBar.VERTICAL = 1;
23559 * Orientation constant - Create a horizontal SplitBar
23563 Roo.SplitBar.HORIZONTAL = 2;
23566 * Placement constant - The resizing element is to the left of the splitter element
23570 Roo.SplitBar.LEFT = 1;
23573 * Placement constant - The resizing element is to the right of the splitter element
23577 Roo.SplitBar.RIGHT = 2;
23580 * Placement constant - The resizing element is positioned above the splitter element
23584 Roo.SplitBar.TOP = 3;
23587 * Placement constant - The resizing element is positioned under splitter element
23591 Roo.SplitBar.BOTTOM = 4;
23594 * Ext JS Library 1.1.1
23595 * Copyright(c) 2006-2007, Ext JS, LLC.
23597 * Originally Released Under LGPL - original licence link has changed is not relivant.
23600 * <script type="text/javascript">
23605 * @extends Roo.util.Observable
23606 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23607 * This class also supports single and multi selection modes. <br>
23608 * Create a data model bound view:
23610 var store = new Roo.data.Store(...);
23612 var view = new Roo.View({
23614 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23616 singleSelect: true,
23617 selectedClass: "ydataview-selected",
23621 // listen for node click?
23622 view.on("click", function(vw, index, node, e){
23623 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23627 dataModel.load("foobar.xml");
23629 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23631 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23632 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23634 * Note: old style constructor is still suported (container, template, config)
23637 * Create a new View
23638 * @param {Object} config The config object
23641 Roo.View = function(config, depreciated_tpl, depreciated_config){
23643 if (typeof(depreciated_tpl) == 'undefined') {
23644 // new way.. - universal constructor.
23645 Roo.apply(this, config);
23646 this.el = Roo.get(this.el);
23649 this.el = Roo.get(config);
23650 this.tpl = depreciated_tpl;
23651 Roo.apply(this, depreciated_config);
23655 if(typeof(this.tpl) == "string"){
23656 this.tpl = new Roo.Template(this.tpl);
23658 // support xtype ctors..
23659 this.tpl = new Roo.factory(this.tpl, Roo);
23663 this.tpl.compile();
23670 * @event beforeclick
23671 * Fires before a click is processed. Returns false to cancel the default action.
23672 * @param {Roo.View} this
23673 * @param {Number} index The index of the target node
23674 * @param {HTMLElement} node The target node
23675 * @param {Roo.EventObject} e The raw event object
23677 "beforeclick" : true,
23680 * Fires when a template node is clicked.
23681 * @param {Roo.View} this
23682 * @param {Number} index The index of the target node
23683 * @param {HTMLElement} node The target node
23684 * @param {Roo.EventObject} e The raw event object
23689 * Fires when a template node is double clicked.
23690 * @param {Roo.View} this
23691 * @param {Number} index The index of the target node
23692 * @param {HTMLElement} node The target node
23693 * @param {Roo.EventObject} e The raw event object
23697 * @event contextmenu
23698 * Fires when a template node is right clicked.
23699 * @param {Roo.View} this
23700 * @param {Number} index The index of the target node
23701 * @param {HTMLElement} node The target node
23702 * @param {Roo.EventObject} e The raw event object
23704 "contextmenu" : true,
23706 * @event selectionchange
23707 * Fires when the selected nodes change.
23708 * @param {Roo.View} this
23709 * @param {Array} selections Array of the selected nodes
23711 "selectionchange" : true,
23714 * @event beforeselect
23715 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23716 * @param {Roo.View} this
23717 * @param {HTMLElement} node The node to be selected
23718 * @param {Array} selections Array of currently selected nodes
23720 "beforeselect" : true,
23722 * @event preparedata
23723 * Fires on every row to render, to allow you to change the data.
23724 * @param {Roo.View} this
23725 * @param {Object} data to be rendered (change this)
23727 "preparedata" : true
23731 "click": this.onClick,
23732 "dblclick": this.onDblClick,
23733 "contextmenu": this.onContextMenu,
23737 this.selections = [];
23739 this.cmp = new Roo.CompositeElementLite([]);
23741 this.store = Roo.factory(this.store, Roo.data);
23742 this.setStore(this.store, true);
23744 Roo.View.superclass.constructor.call(this);
23747 Roo.extend(Roo.View, Roo.util.Observable, {
23750 * @cfg {Roo.data.Store} store Data store to load data from.
23755 * @cfg {String|Roo.Element} el The container element.
23760 * @cfg {String|Roo.Template} tpl The template used by this View
23764 * @cfg {String} dataName the named area of the template to use as the data area
23765 * Works with domtemplates roo-name="name"
23769 * @cfg {String} selectedClass The css class to add to selected nodes
23771 selectedClass : "x-view-selected",
23773 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23777 * @cfg {Boolean} multiSelect Allow multiple selection
23779 multiSelect : false,
23781 * @cfg {Boolean} singleSelect Allow single selection
23783 singleSelect: false,
23786 * @cfg {Boolean} toggleSelect - selecting
23788 toggleSelect : false,
23791 * Returns the element this view is bound to.
23792 * @return {Roo.Element}
23794 getEl : function(){
23799 * Refreshes the view.
23801 refresh : function(){
23804 // if we are using something like 'domtemplate', then
23805 // the what gets used is:
23806 // t.applySubtemplate(NAME, data, wrapping data..)
23807 // the outer template then get' applied with
23808 // the store 'extra data'
23809 // and the body get's added to the
23810 // roo-name="data" node?
23811 // <span class='roo-tpl-{name}'></span> ?????
23815 this.clearSelections();
23816 this.el.update("");
23818 var records = this.store.getRange();
23819 if(records.length < 1) {
23821 // is this valid?? = should it render a template??
23823 this.el.update(this.emptyText);
23827 if (this.dataName) {
23828 this.el.update(t.apply(this.store.meta)); //????
23829 el = this.el.child('.roo-tpl-' + this.dataName);
23832 for(var i = 0, len = records.length; i < len; i++){
23833 var data = this.prepareData(records[i].data, i, records[i]);
23834 this.fireEvent("preparedata", this, data, i, records[i]);
23835 html[html.length] = Roo.util.Format.trim(
23837 t.applySubtemplate(this.dataName, data, this.store.meta) :
23844 el.update(html.join(""));
23845 this.nodes = el.dom.childNodes;
23846 this.updateIndexes(0);
23850 * Function to override to reformat the data that is sent to
23851 * the template for each node.
23852 * DEPRICATED - use the preparedata event handler.
23853 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23854 * a JSON object for an UpdateManager bound view).
23856 prepareData : function(data, index, record)
23858 this.fireEvent("preparedata", this, data, index, record);
23862 onUpdate : function(ds, record){
23863 this.clearSelections();
23864 var index = this.store.indexOf(record);
23865 var n = this.nodes[index];
23866 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
23867 n.parentNode.removeChild(n);
23868 this.updateIndexes(index, index);
23874 onAdd : function(ds, records, index)
23876 this.clearSelections();
23877 if(this.nodes.length == 0){
23881 var n = this.nodes[index];
23882 for(var i = 0, len = records.length; i < len; i++){
23883 var d = this.prepareData(records[i].data, i, records[i]);
23885 this.tpl.insertBefore(n, d);
23888 this.tpl.append(this.el, d);
23891 this.updateIndexes(index);
23894 onRemove : function(ds, record, index){
23895 this.clearSelections();
23896 var el = this.dataName ?
23897 this.el.child('.roo-tpl-' + this.dataName) :
23899 el.dom.removeChild(this.nodes[index]);
23900 this.updateIndexes(index);
23904 * Refresh an individual node.
23905 * @param {Number} index
23907 refreshNode : function(index){
23908 this.onUpdate(this.store, this.store.getAt(index));
23911 updateIndexes : function(startIndex, endIndex){
23912 var ns = this.nodes;
23913 startIndex = startIndex || 0;
23914 endIndex = endIndex || ns.length - 1;
23915 for(var i = startIndex; i <= endIndex; i++){
23916 ns[i].nodeIndex = i;
23921 * Changes the data store this view uses and refresh the view.
23922 * @param {Store} store
23924 setStore : function(store, initial){
23925 if(!initial && this.store){
23926 this.store.un("datachanged", this.refresh);
23927 this.store.un("add", this.onAdd);
23928 this.store.un("remove", this.onRemove);
23929 this.store.un("update", this.onUpdate);
23930 this.store.un("clear", this.refresh);
23934 store.on("datachanged", this.refresh, this);
23935 store.on("add", this.onAdd, this);
23936 store.on("remove", this.onRemove, this);
23937 store.on("update", this.onUpdate, this);
23938 store.on("clear", this.refresh, this);
23947 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23948 * @param {HTMLElement} node
23949 * @return {HTMLElement} The template node
23951 findItemFromChild : function(node){
23952 var el = this.dataName ?
23953 this.el.child('.roo-tpl-' + this.dataName,true) :
23956 if(!node || node.parentNode == el){
23959 var p = node.parentNode;
23960 while(p && p != el){
23961 if(p.parentNode == el){
23970 onClick : function(e){
23971 var item = this.findItemFromChild(e.getTarget());
23973 var index = this.indexOf(item);
23974 if(this.onItemClick(item, index, e) !== false){
23975 this.fireEvent("click", this, index, item, e);
23978 this.clearSelections();
23983 onContextMenu : function(e){
23984 var item = this.findItemFromChild(e.getTarget());
23986 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23991 onDblClick : function(e){
23992 var item = this.findItemFromChild(e.getTarget());
23994 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23998 onItemClick : function(item, index, e)
24000 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24003 if (this.toggleSelect) {
24004 var m = this.isSelected(item) ? 'unselect' : 'select';
24007 _t[m](item, true, false);
24010 if(this.multiSelect || this.singleSelect){
24011 if(this.multiSelect && e.shiftKey && this.lastSelection){
24012 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24014 this.select(item, this.multiSelect && e.ctrlKey);
24015 this.lastSelection = item;
24017 e.preventDefault();
24023 * Get the number of selected nodes.
24026 getSelectionCount : function(){
24027 return this.selections.length;
24031 * Get the currently selected nodes.
24032 * @return {Array} An array of HTMLElements
24034 getSelectedNodes : function(){
24035 return this.selections;
24039 * Get the indexes of the selected nodes.
24042 getSelectedIndexes : function(){
24043 var indexes = [], s = this.selections;
24044 for(var i = 0, len = s.length; i < len; i++){
24045 indexes.push(s[i].nodeIndex);
24051 * Clear all selections
24052 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24054 clearSelections : function(suppressEvent){
24055 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24056 this.cmp.elements = this.selections;
24057 this.cmp.removeClass(this.selectedClass);
24058 this.selections = [];
24059 if(!suppressEvent){
24060 this.fireEvent("selectionchange", this, this.selections);
24066 * Returns true if the passed node is selected
24067 * @param {HTMLElement/Number} node The node or node index
24068 * @return {Boolean}
24070 isSelected : function(node){
24071 var s = this.selections;
24075 node = this.getNode(node);
24076 return s.indexOf(node) !== -1;
24081 * @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
24082 * @param {Boolean} keepExisting (optional) true to keep existing selections
24083 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24085 select : function(nodeInfo, keepExisting, suppressEvent){
24086 if(nodeInfo instanceof Array){
24088 this.clearSelections(true);
24090 for(var i = 0, len = nodeInfo.length; i < len; i++){
24091 this.select(nodeInfo[i], true, true);
24095 var node = this.getNode(nodeInfo);
24096 if(!node || this.isSelected(node)){
24097 return; // already selected.
24100 this.clearSelections(true);
24102 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24103 Roo.fly(node).addClass(this.selectedClass);
24104 this.selections.push(node);
24105 if(!suppressEvent){
24106 this.fireEvent("selectionchange", this, this.selections);
24114 * @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
24115 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24116 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24118 unselect : function(nodeInfo, keepExisting, suppressEvent)
24120 if(nodeInfo instanceof Array){
24121 Roo.each(this.selections, function(s) {
24122 this.unselect(s, nodeInfo);
24126 var node = this.getNode(nodeInfo);
24127 if(!node || !this.isSelected(node)){
24128 Roo.log("not selected");
24129 return; // not selected.
24133 Roo.each(this.selections, function(s) {
24135 Roo.fly(node).removeClass(this.selectedClass);
24142 this.selections= ns;
24143 this.fireEvent("selectionchange", this, this.selections);
24147 * Gets a template node.
24148 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24149 * @return {HTMLElement} The node or null if it wasn't found
24151 getNode : function(nodeInfo){
24152 if(typeof nodeInfo == "string"){
24153 return document.getElementById(nodeInfo);
24154 }else if(typeof nodeInfo == "number"){
24155 return this.nodes[nodeInfo];
24161 * Gets a range template nodes.
24162 * @param {Number} startIndex
24163 * @param {Number} endIndex
24164 * @return {Array} An array of nodes
24166 getNodes : function(start, end){
24167 var ns = this.nodes;
24168 start = start || 0;
24169 end = typeof end == "undefined" ? ns.length - 1 : end;
24172 for(var i = start; i <= end; i++){
24176 for(var i = start; i >= end; i--){
24184 * Finds the index of the passed node
24185 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24186 * @return {Number} The index of the node or -1
24188 indexOf : function(node){
24189 node = this.getNode(node);
24190 if(typeof node.nodeIndex == "number"){
24191 return node.nodeIndex;
24193 var ns = this.nodes;
24194 for(var i = 0, len = ns.length; i < len; i++){
24204 * Ext JS Library 1.1.1
24205 * Copyright(c) 2006-2007, Ext JS, LLC.
24207 * Originally Released Under LGPL - original licence link has changed is not relivant.
24210 * <script type="text/javascript">
24214 * @class Roo.JsonView
24215 * @extends Roo.View
24216 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24218 var view = new Roo.JsonView({
24219 container: "my-element",
24220 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24225 // listen for node click?
24226 view.on("click", function(vw, index, node, e){
24227 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24230 // direct load of JSON data
24231 view.load("foobar.php");
24233 // Example from my blog list
24234 var tpl = new Roo.Template(
24235 '<div class="entry">' +
24236 '<a class="entry-title" href="{link}">{title}</a>' +
24237 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24238 "</div><hr />"
24241 var moreView = new Roo.JsonView({
24242 container : "entry-list",
24246 moreView.on("beforerender", this.sortEntries, this);
24248 url: "/blog/get-posts.php",
24249 params: "allposts=true",
24250 text: "Loading Blog Entries..."
24254 * Note: old code is supported with arguments : (container, template, config)
24258 * Create a new JsonView
24260 * @param {Object} config The config object
24263 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24266 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24268 var um = this.el.getUpdateManager();
24269 um.setRenderer(this);
24270 um.on("update", this.onLoad, this);
24271 um.on("failure", this.onLoadException, this);
24274 * @event beforerender
24275 * Fires before rendering of the downloaded JSON data.
24276 * @param {Roo.JsonView} this
24277 * @param {Object} data The JSON data loaded
24281 * Fires when data is loaded.
24282 * @param {Roo.JsonView} this
24283 * @param {Object} data The JSON data loaded
24284 * @param {Object} response The raw Connect response object
24287 * @event loadexception
24288 * Fires when loading fails.
24289 * @param {Roo.JsonView} this
24290 * @param {Object} response The raw Connect response object
24293 'beforerender' : true,
24295 'loadexception' : true
24298 Roo.extend(Roo.JsonView, Roo.View, {
24300 * @type {String} The root property in the loaded JSON object that contains the data
24305 * Refreshes the view.
24307 refresh : function(){
24308 this.clearSelections();
24309 this.el.update("");
24311 var o = this.jsonData;
24312 if(o && o.length > 0){
24313 for(var i = 0, len = o.length; i < len; i++){
24314 var data = this.prepareData(o[i], i, o);
24315 html[html.length] = this.tpl.apply(data);
24318 html.push(this.emptyText);
24320 this.el.update(html.join(""));
24321 this.nodes = this.el.dom.childNodes;
24322 this.updateIndexes(0);
24326 * 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.
24327 * @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:
24330 url: "your-url.php",
24331 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24332 callback: yourFunction,
24333 scope: yourObject, //(optional scope)
24336 text: "Loading...",
24341 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24342 * 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.
24343 * @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}
24344 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24345 * @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.
24348 var um = this.el.getUpdateManager();
24349 um.update.apply(um, arguments);
24352 render : function(el, response){
24353 this.clearSelections();
24354 this.el.update("");
24357 o = Roo.util.JSON.decode(response.responseText);
24360 o = o[this.jsonRoot];
24365 * The current JSON data or null
24368 this.beforeRender();
24373 * Get the number of records in the current JSON dataset
24376 getCount : function(){
24377 return this.jsonData ? this.jsonData.length : 0;
24381 * Returns the JSON object for the specified node(s)
24382 * @param {HTMLElement/Array} node The node or an array of nodes
24383 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24384 * you get the JSON object for the node
24386 getNodeData : function(node){
24387 if(node instanceof Array){
24389 for(var i = 0, len = node.length; i < len; i++){
24390 data.push(this.getNodeData(node[i]));
24394 return this.jsonData[this.indexOf(node)] || null;
24397 beforeRender : function(){
24398 this.snapshot = this.jsonData;
24400 this.sort.apply(this, this.sortInfo);
24402 this.fireEvent("beforerender", this, this.jsonData);
24405 onLoad : function(el, o){
24406 this.fireEvent("load", this, this.jsonData, o);
24409 onLoadException : function(el, o){
24410 this.fireEvent("loadexception", this, o);
24414 * Filter the data by a specific property.
24415 * @param {String} property A property on your JSON objects
24416 * @param {String/RegExp} value Either string that the property values
24417 * should start with, or a RegExp to test against the property
24419 filter : function(property, value){
24422 var ss = this.snapshot;
24423 if(typeof value == "string"){
24424 var vlen = value.length;
24426 this.clearFilter();
24429 value = value.toLowerCase();
24430 for(var i = 0, len = ss.length; i < len; i++){
24432 if(o[property].substr(0, vlen).toLowerCase() == value){
24436 } else if(value.exec){ // regex?
24437 for(var i = 0, len = ss.length; i < len; i++){
24439 if(value.test(o[property])){
24446 this.jsonData = data;
24452 * Filter by a function. The passed function will be called with each
24453 * object in the current dataset. If the function returns true the value is kept,
24454 * otherwise it is filtered.
24455 * @param {Function} fn
24456 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24458 filterBy : function(fn, scope){
24461 var ss = this.snapshot;
24462 for(var i = 0, len = ss.length; i < len; i++){
24464 if(fn.call(scope || this, o)){
24468 this.jsonData = data;
24474 * Clears the current filter.
24476 clearFilter : function(){
24477 if(this.snapshot && this.jsonData != this.snapshot){
24478 this.jsonData = this.snapshot;
24485 * Sorts the data for this view and refreshes it.
24486 * @param {String} property A property on your JSON objects to sort on
24487 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24488 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24490 sort : function(property, dir, sortType){
24491 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24494 var dsc = dir && dir.toLowerCase() == "desc";
24495 var f = function(o1, o2){
24496 var v1 = sortType ? sortType(o1[p]) : o1[p];
24497 var v2 = sortType ? sortType(o2[p]) : o2[p];
24500 return dsc ? +1 : -1;
24501 } else if(v1 > v2){
24502 return dsc ? -1 : +1;
24507 this.jsonData.sort(f);
24509 if(this.jsonData != this.snapshot){
24510 this.snapshot.sort(f);
24516 * Ext JS Library 1.1.1
24517 * Copyright(c) 2006-2007, Ext JS, LLC.
24519 * Originally Released Under LGPL - original licence link has changed is not relivant.
24522 * <script type="text/javascript">
24527 * @class Roo.ColorPalette
24528 * @extends Roo.Component
24529 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24530 * Here's an example of typical usage:
24532 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24533 cp.render('my-div');
24535 cp.on('select', function(palette, selColor){
24536 // do something with selColor
24540 * Create a new ColorPalette
24541 * @param {Object} config The config object
24543 Roo.ColorPalette = function(config){
24544 Roo.ColorPalette.superclass.constructor.call(this, config);
24548 * Fires when a color is selected
24549 * @param {ColorPalette} this
24550 * @param {String} color The 6-digit color hex code (without the # symbol)
24556 this.on("select", this.handler, this.scope, true);
24559 Roo.extend(Roo.ColorPalette, Roo.Component, {
24561 * @cfg {String} itemCls
24562 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24564 itemCls : "x-color-palette",
24566 * @cfg {String} value
24567 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24568 * the hex codes are case-sensitive.
24571 clickEvent:'click',
24573 ctype: "Roo.ColorPalette",
24576 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24578 allowReselect : false,
24581 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24582 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24583 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24584 * of colors with the width setting until the box is symmetrical.</p>
24585 * <p>You can override individual colors if needed:</p>
24587 var cp = new Roo.ColorPalette();
24588 cp.colors[0] = "FF0000"; // change the first box to red
24591 Or you can provide a custom array of your own for complete control:
24593 var cp = new Roo.ColorPalette();
24594 cp.colors = ["000000", "993300", "333300"];
24599 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24600 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24601 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24602 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24603 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24607 onRender : function(container, position){
24608 var t = new Roo.MasterTemplate(
24609 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24611 var c = this.colors;
24612 for(var i = 0, len = c.length; i < len; i++){
24615 var el = document.createElement("div");
24616 el.className = this.itemCls;
24618 container.dom.insertBefore(el, position);
24619 this.el = Roo.get(el);
24620 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24621 if(this.clickEvent != 'click'){
24622 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24627 afterRender : function(){
24628 Roo.ColorPalette.superclass.afterRender.call(this);
24630 var s = this.value;
24637 handleClick : function(e, t){
24638 e.preventDefault();
24639 if(!this.disabled){
24640 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24641 this.select(c.toUpperCase());
24646 * Selects the specified color in the palette (fires the select event)
24647 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24649 select : function(color){
24650 color = color.replace("#", "");
24651 if(color != this.value || this.allowReselect){
24654 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24656 el.child("a.color-"+color).addClass("x-color-palette-sel");
24657 this.value = color;
24658 this.fireEvent("select", this, color);
24663 * Ext JS Library 1.1.1
24664 * Copyright(c) 2006-2007, Ext JS, LLC.
24666 * Originally Released Under LGPL - original licence link has changed is not relivant.
24669 * <script type="text/javascript">
24673 * @class Roo.DatePicker
24674 * @extends Roo.Component
24675 * Simple date picker class.
24677 * Create a new DatePicker
24678 * @param {Object} config The config object
24680 Roo.DatePicker = function(config){
24681 Roo.DatePicker.superclass.constructor.call(this, config);
24683 this.value = config && config.value ?
24684 config.value.clearTime() : new Date().clearTime();
24689 * Fires when a date is selected
24690 * @param {DatePicker} this
24691 * @param {Date} date The selected date
24695 * @event monthchange
24696 * Fires when the displayed month changes
24697 * @param {DatePicker} this
24698 * @param {Date} date The selected month
24700 'monthchange': true
24704 this.on("select", this.handler, this.scope || this);
24706 // build the disabledDatesRE
24707 if(!this.disabledDatesRE && this.disabledDates){
24708 var dd = this.disabledDates;
24710 for(var i = 0; i < dd.length; i++){
24712 if(i != dd.length-1) re += "|";
24714 this.disabledDatesRE = new RegExp(re + ")");
24718 Roo.extend(Roo.DatePicker, Roo.Component, {
24720 * @cfg {String} todayText
24721 * The text to display on the button that selects the current date (defaults to "Today")
24723 todayText : "Today",
24725 * @cfg {String} okText
24726 * The text to display on the ok button
24728 okText : " OK ", //   to give the user extra clicking room
24730 * @cfg {String} cancelText
24731 * The text to display on the cancel button
24733 cancelText : "Cancel",
24735 * @cfg {String} todayTip
24736 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24738 todayTip : "{0} (Spacebar)",
24740 * @cfg {Date} minDate
24741 * Minimum allowable date (JavaScript date object, defaults to null)
24745 * @cfg {Date} maxDate
24746 * Maximum allowable date (JavaScript date object, defaults to null)
24750 * @cfg {String} minText
24751 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24753 minText : "This date is before the minimum date",
24755 * @cfg {String} maxText
24756 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24758 maxText : "This date is after the maximum date",
24760 * @cfg {String} format
24761 * The default date format string which can be overriden for localization support. The format must be
24762 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24766 * @cfg {Array} disabledDays
24767 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24769 disabledDays : null,
24771 * @cfg {String} disabledDaysText
24772 * The tooltip to display when the date falls on a disabled day (defaults to "")
24774 disabledDaysText : "",
24776 * @cfg {RegExp} disabledDatesRE
24777 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24779 disabledDatesRE : null,
24781 * @cfg {String} disabledDatesText
24782 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24784 disabledDatesText : "",
24786 * @cfg {Boolean} constrainToViewport
24787 * True to constrain the date picker to the viewport (defaults to true)
24789 constrainToViewport : true,
24791 * @cfg {Array} monthNames
24792 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24794 monthNames : Date.monthNames,
24796 * @cfg {Array} dayNames
24797 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24799 dayNames : Date.dayNames,
24801 * @cfg {String} nextText
24802 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24804 nextText: 'Next Month (Control+Right)',
24806 * @cfg {String} prevText
24807 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24809 prevText: 'Previous Month (Control+Left)',
24811 * @cfg {String} monthYearText
24812 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24814 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24816 * @cfg {Number} startDay
24817 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24821 * @cfg {Bool} showClear
24822 * Show a clear button (usefull for date form elements that can be blank.)
24828 * Sets the value of the date field
24829 * @param {Date} value The date to set
24831 setValue : function(value){
24832 var old = this.value;
24833 this.value = value.clearTime(true);
24835 this.update(this.value);
24840 * Gets the current selected value of the date field
24841 * @return {Date} The selected date
24843 getValue : function(){
24848 focus : function(){
24850 this.update(this.activeDate);
24855 onRender : function(container, position){
24857 '<table cellspacing="0">',
24858 '<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>',
24859 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24860 var dn = this.dayNames;
24861 for(var i = 0; i < 7; i++){
24862 var d = this.startDay+i;
24866 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24868 m[m.length] = "</tr></thead><tbody><tr>";
24869 for(var i = 0; i < 42; i++) {
24870 if(i % 7 == 0 && i != 0){
24871 m[m.length] = "</tr><tr>";
24873 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24875 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24876 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24878 var el = document.createElement("div");
24879 el.className = "x-date-picker";
24880 el.innerHTML = m.join("");
24882 container.dom.insertBefore(el, position);
24884 this.el = Roo.get(el);
24885 this.eventEl = Roo.get(el.firstChild);
24887 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24888 handler: this.showPrevMonth,
24890 preventDefault:true,
24894 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24895 handler: this.showNextMonth,
24897 preventDefault:true,
24901 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24903 this.monthPicker = this.el.down('div.x-date-mp');
24904 this.monthPicker.enableDisplayMode('block');
24906 var kn = new Roo.KeyNav(this.eventEl, {
24907 "left" : function(e){
24909 this.showPrevMonth() :
24910 this.update(this.activeDate.add("d", -1));
24913 "right" : function(e){
24915 this.showNextMonth() :
24916 this.update(this.activeDate.add("d", 1));
24919 "up" : function(e){
24921 this.showNextYear() :
24922 this.update(this.activeDate.add("d", -7));
24925 "down" : function(e){
24927 this.showPrevYear() :
24928 this.update(this.activeDate.add("d", 7));
24931 "pageUp" : function(e){
24932 this.showNextMonth();
24935 "pageDown" : function(e){
24936 this.showPrevMonth();
24939 "enter" : function(e){
24940 e.stopPropagation();
24947 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24949 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24951 this.el.unselectable();
24953 this.cells = this.el.select("table.x-date-inner tbody td");
24954 this.textNodes = this.el.query("table.x-date-inner tbody span");
24956 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24958 tooltip: this.monthYearText
24961 this.mbtn.on('click', this.showMonthPicker, this);
24962 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24965 var today = (new Date()).dateFormat(this.format);
24967 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24968 if (this.showClear) {
24969 baseTb.add( new Roo.Toolbar.Fill());
24972 text: String.format(this.todayText, today),
24973 tooltip: String.format(this.todayTip, today),
24974 handler: this.selectToday,
24978 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24981 if (this.showClear) {
24983 baseTb.add( new Roo.Toolbar.Fill());
24986 cls: 'x-btn-icon x-btn-clear',
24987 handler: function() {
24989 this.fireEvent("select", this, '');
24999 this.update(this.value);
25002 createMonthPicker : function(){
25003 if(!this.monthPicker.dom.firstChild){
25004 var buf = ['<table border="0" cellspacing="0">'];
25005 for(var i = 0; i < 6; i++){
25007 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25008 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25010 '<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>' :
25011 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25015 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25017 '</button><button type="button" class="x-date-mp-cancel">',
25019 '</button></td></tr>',
25022 this.monthPicker.update(buf.join(''));
25023 this.monthPicker.on('click', this.onMonthClick, this);
25024 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25026 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25027 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25029 this.mpMonths.each(function(m, a, i){
25032 m.dom.xmonth = 5 + Math.round(i * .5);
25034 m.dom.xmonth = Math.round((i-1) * .5);
25040 showMonthPicker : function(){
25041 this.createMonthPicker();
25042 var size = this.el.getSize();
25043 this.monthPicker.setSize(size);
25044 this.monthPicker.child('table').setSize(size);
25046 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25047 this.updateMPMonth(this.mpSelMonth);
25048 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25049 this.updateMPYear(this.mpSelYear);
25051 this.monthPicker.slideIn('t', {duration:.2});
25054 updateMPYear : function(y){
25056 var ys = this.mpYears.elements;
25057 for(var i = 1; i <= 10; i++){
25058 var td = ys[i-1], y2;
25060 y2 = y + Math.round(i * .5);
25061 td.firstChild.innerHTML = y2;
25064 y2 = y - (5-Math.round(i * .5));
25065 td.firstChild.innerHTML = y2;
25068 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25072 updateMPMonth : function(sm){
25073 this.mpMonths.each(function(m, a, i){
25074 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25078 selectMPMonth: function(m){
25082 onMonthClick : function(e, t){
25084 var el = new Roo.Element(t), pn;
25085 if(el.is('button.x-date-mp-cancel')){
25086 this.hideMonthPicker();
25088 else if(el.is('button.x-date-mp-ok')){
25089 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25090 this.hideMonthPicker();
25092 else if(pn = el.up('td.x-date-mp-month', 2)){
25093 this.mpMonths.removeClass('x-date-mp-sel');
25094 pn.addClass('x-date-mp-sel');
25095 this.mpSelMonth = pn.dom.xmonth;
25097 else if(pn = el.up('td.x-date-mp-year', 2)){
25098 this.mpYears.removeClass('x-date-mp-sel');
25099 pn.addClass('x-date-mp-sel');
25100 this.mpSelYear = pn.dom.xyear;
25102 else if(el.is('a.x-date-mp-prev')){
25103 this.updateMPYear(this.mpyear-10);
25105 else if(el.is('a.x-date-mp-next')){
25106 this.updateMPYear(this.mpyear+10);
25110 onMonthDblClick : function(e, t){
25112 var el = new Roo.Element(t), pn;
25113 if(pn = el.up('td.x-date-mp-month', 2)){
25114 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25115 this.hideMonthPicker();
25117 else if(pn = el.up('td.x-date-mp-year', 2)){
25118 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25119 this.hideMonthPicker();
25123 hideMonthPicker : function(disableAnim){
25124 if(this.monthPicker){
25125 if(disableAnim === true){
25126 this.monthPicker.hide();
25128 this.monthPicker.slideOut('t', {duration:.2});
25134 showPrevMonth : function(e){
25135 this.update(this.activeDate.add("mo", -1));
25139 showNextMonth : function(e){
25140 this.update(this.activeDate.add("mo", 1));
25144 showPrevYear : function(){
25145 this.update(this.activeDate.add("y", -1));
25149 showNextYear : function(){
25150 this.update(this.activeDate.add("y", 1));
25154 handleMouseWheel : function(e){
25155 var delta = e.getWheelDelta();
25157 this.showPrevMonth();
25159 } else if(delta < 0){
25160 this.showNextMonth();
25166 handleDateClick : function(e, t){
25168 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25169 this.setValue(new Date(t.dateValue));
25170 this.fireEvent("select", this, this.value);
25175 selectToday : function(){
25176 this.setValue(new Date().clearTime());
25177 this.fireEvent("select", this, this.value);
25181 update : function(date)
25183 var vd = this.activeDate;
25184 this.activeDate = date;
25186 var t = date.getTime();
25187 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25188 this.cells.removeClass("x-date-selected");
25189 this.cells.each(function(c){
25190 if(c.dom.firstChild.dateValue == t){
25191 c.addClass("x-date-selected");
25192 setTimeout(function(){
25193 try{c.dom.firstChild.focus();}catch(e){}
25202 var days = date.getDaysInMonth();
25203 var firstOfMonth = date.getFirstDateOfMonth();
25204 var startingPos = firstOfMonth.getDay()-this.startDay;
25206 if(startingPos <= this.startDay){
25210 var pm = date.add("mo", -1);
25211 var prevStart = pm.getDaysInMonth()-startingPos;
25213 var cells = this.cells.elements;
25214 var textEls = this.textNodes;
25215 days += startingPos;
25217 // convert everything to numbers so it's fast
25218 var day = 86400000;
25219 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25220 var today = new Date().clearTime().getTime();
25221 var sel = date.clearTime().getTime();
25222 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25223 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25224 var ddMatch = this.disabledDatesRE;
25225 var ddText = this.disabledDatesText;
25226 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25227 var ddaysText = this.disabledDaysText;
25228 var format = this.format;
25230 var setCellClass = function(cal, cell){
25232 var t = d.getTime();
25233 cell.firstChild.dateValue = t;
25235 cell.className += " x-date-today";
25236 cell.title = cal.todayText;
25239 cell.className += " x-date-selected";
25240 setTimeout(function(){
25241 try{cell.firstChild.focus();}catch(e){}
25246 cell.className = " x-date-disabled";
25247 cell.title = cal.minText;
25251 cell.className = " x-date-disabled";
25252 cell.title = cal.maxText;
25256 if(ddays.indexOf(d.getDay()) != -1){
25257 cell.title = ddaysText;
25258 cell.className = " x-date-disabled";
25261 if(ddMatch && format){
25262 var fvalue = d.dateFormat(format);
25263 if(ddMatch.test(fvalue)){
25264 cell.title = ddText.replace("%0", fvalue);
25265 cell.className = " x-date-disabled";
25271 for(; i < startingPos; i++) {
25272 textEls[i].innerHTML = (++prevStart);
25273 d.setDate(d.getDate()+1);
25274 cells[i].className = "x-date-prevday";
25275 setCellClass(this, cells[i]);
25277 for(; i < days; i++){
25278 intDay = i - startingPos + 1;
25279 textEls[i].innerHTML = (intDay);
25280 d.setDate(d.getDate()+1);
25281 cells[i].className = "x-date-active";
25282 setCellClass(this, cells[i]);
25285 for(; i < 42; i++) {
25286 textEls[i].innerHTML = (++extraDays);
25287 d.setDate(d.getDate()+1);
25288 cells[i].className = "x-date-nextday";
25289 setCellClass(this, cells[i]);
25292 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25293 this.fireEvent('monthchange', this, date);
25295 if(!this.internalRender){
25296 var main = this.el.dom.firstChild;
25297 var w = main.offsetWidth;
25298 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25299 Roo.fly(main).setWidth(w);
25300 this.internalRender = true;
25301 // opera does not respect the auto grow header center column
25302 // then, after it gets a width opera refuses to recalculate
25303 // without a second pass
25304 if(Roo.isOpera && !this.secondPass){
25305 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25306 this.secondPass = true;
25307 this.update.defer(10, this, [date]);
25315 * Ext JS Library 1.1.1
25316 * Copyright(c) 2006-2007, Ext JS, LLC.
25318 * Originally Released Under LGPL - original licence link has changed is not relivant.
25321 * <script type="text/javascript">
25324 * @class Roo.TabPanel
25325 * @extends Roo.util.Observable
25326 * A lightweight tab container.
25330 // basic tabs 1, built from existing content
25331 var tabs = new Roo.TabPanel("tabs1");
25332 tabs.addTab("script", "View Script");
25333 tabs.addTab("markup", "View Markup");
25334 tabs.activate("script");
25336 // more advanced tabs, built from javascript
25337 var jtabs = new Roo.TabPanel("jtabs");
25338 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25340 // set up the UpdateManager
25341 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25342 var updater = tab2.getUpdateManager();
25343 updater.setDefaultUrl("ajax1.htm");
25344 tab2.on('activate', updater.refresh, updater, true);
25346 // Use setUrl for Ajax loading
25347 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25348 tab3.setUrl("ajax2.htm", null, true);
25351 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25354 jtabs.activate("jtabs-1");
25357 * Create a new TabPanel.
25358 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25359 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25361 Roo.TabPanel = function(container, config){
25363 * The container element for this TabPanel.
25364 * @type Roo.Element
25366 this.el = Roo.get(container, true);
25368 if(typeof config == "boolean"){
25369 this.tabPosition = config ? "bottom" : "top";
25371 Roo.apply(this, config);
25374 if(this.tabPosition == "bottom"){
25375 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25376 this.el.addClass("x-tabs-bottom");
25378 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25379 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25380 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25382 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25384 if(this.tabPosition != "bottom"){
25385 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25386 * @type Roo.Element
25388 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25389 this.el.addClass("x-tabs-top");
25393 this.bodyEl.setStyle("position", "relative");
25395 this.active = null;
25396 this.activateDelegate = this.activate.createDelegate(this);
25401 * Fires when the active tab changes
25402 * @param {Roo.TabPanel} this
25403 * @param {Roo.TabPanelItem} activePanel The new active tab
25407 * @event beforetabchange
25408 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25409 * @param {Roo.TabPanel} this
25410 * @param {Object} e Set cancel to true on this object to cancel the tab change
25411 * @param {Roo.TabPanelItem} tab The tab being changed to
25413 "beforetabchange" : true
25416 Roo.EventManager.onWindowResize(this.onResize, this);
25417 this.cpad = this.el.getPadding("lr");
25418 this.hiddenCount = 0;
25421 // toolbar on the tabbar support...
25422 if (this.toolbar) {
25423 var tcfg = this.toolbar;
25424 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25425 this.toolbar = new Roo.Toolbar(tcfg);
25426 if (Roo.isSafari) {
25427 var tbl = tcfg.container.child('table', true);
25428 tbl.setAttribute('width', '100%');
25435 Roo.TabPanel.superclass.constructor.call(this);
25438 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25440 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25442 tabPosition : "top",
25444 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25446 currentTabWidth : 0,
25448 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25452 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25456 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25458 preferredTabWidth : 175,
25460 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25462 resizeTabs : false,
25464 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25466 monitorResize : true,
25468 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25473 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25474 * @param {String} id The id of the div to use <b>or create</b>
25475 * @param {String} text The text for the tab
25476 * @param {String} content (optional) Content to put in the TabPanelItem body
25477 * @param {Boolean} closable (optional) True to create a close icon on the tab
25478 * @return {Roo.TabPanelItem} The created TabPanelItem
25480 addTab : function(id, text, content, closable){
25481 var item = new Roo.TabPanelItem(this, id, text, closable);
25482 this.addTabItem(item);
25484 item.setContent(content);
25490 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25491 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25492 * @return {Roo.TabPanelItem}
25494 getTab : function(id){
25495 return this.items[id];
25499 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25500 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25502 hideTab : function(id){
25503 var t = this.items[id];
25506 this.hiddenCount++;
25507 this.autoSizeTabs();
25512 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25513 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25515 unhideTab : function(id){
25516 var t = this.items[id];
25518 t.setHidden(false);
25519 this.hiddenCount--;
25520 this.autoSizeTabs();
25525 * Adds an existing {@link Roo.TabPanelItem}.
25526 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25528 addTabItem : function(item){
25529 this.items[item.id] = item;
25530 this.items.push(item);
25531 if(this.resizeTabs){
25532 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25533 this.autoSizeTabs();
25540 * Removes a {@link Roo.TabPanelItem}.
25541 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25543 removeTab : function(id){
25544 var items = this.items;
25545 var tab = items[id];
25546 if(!tab) { return; }
25547 var index = items.indexOf(tab);
25548 if(this.active == tab && items.length > 1){
25549 var newTab = this.getNextAvailable(index);
25554 this.stripEl.dom.removeChild(tab.pnode.dom);
25555 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25556 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25558 items.splice(index, 1);
25559 delete this.items[tab.id];
25560 tab.fireEvent("close", tab);
25561 tab.purgeListeners();
25562 this.autoSizeTabs();
25565 getNextAvailable : function(start){
25566 var items = this.items;
25568 // look for a next tab that will slide over to
25569 // replace the one being removed
25570 while(index < items.length){
25571 var item = items[++index];
25572 if(item && !item.isHidden()){
25576 // if one isn't found select the previous tab (on the left)
25579 var item = items[--index];
25580 if(item && !item.isHidden()){
25588 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25589 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25591 disableTab : function(id){
25592 var tab = this.items[id];
25593 if(tab && this.active != tab){
25599 * Enables a {@link Roo.TabPanelItem} that is disabled.
25600 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25602 enableTab : function(id){
25603 var tab = this.items[id];
25608 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25609 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25610 * @return {Roo.TabPanelItem} The TabPanelItem.
25612 activate : function(id){
25613 var tab = this.items[id];
25617 if(tab == this.active || tab.disabled){
25621 this.fireEvent("beforetabchange", this, e, tab);
25622 if(e.cancel !== true && !tab.disabled){
25624 this.active.hide();
25626 this.active = this.items[id];
25627 this.active.show();
25628 this.fireEvent("tabchange", this, this.active);
25634 * Gets the active {@link Roo.TabPanelItem}.
25635 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25637 getActiveTab : function(){
25638 return this.active;
25642 * Updates the tab body element to fit the height of the container element
25643 * for overflow scrolling
25644 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25646 syncHeight : function(targetHeight){
25647 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25648 var bm = this.bodyEl.getMargins();
25649 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25650 this.bodyEl.setHeight(newHeight);
25654 onResize : function(){
25655 if(this.monitorResize){
25656 this.autoSizeTabs();
25661 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25663 beginUpdate : function(){
25664 this.updating = true;
25668 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25670 endUpdate : function(){
25671 this.updating = false;
25672 this.autoSizeTabs();
25676 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25678 autoSizeTabs : function(){
25679 var count = this.items.length;
25680 var vcount = count - this.hiddenCount;
25681 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25682 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25683 var availWidth = Math.floor(w / vcount);
25684 var b = this.stripBody;
25685 if(b.getWidth() > w){
25686 var tabs = this.items;
25687 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25688 if(availWidth < this.minTabWidth){
25689 /*if(!this.sleft){ // incomplete scrolling code
25690 this.createScrollButtons();
25693 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25696 if(this.currentTabWidth < this.preferredTabWidth){
25697 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25703 * Returns the number of tabs in this TabPanel.
25706 getCount : function(){
25707 return this.items.length;
25711 * Resizes all the tabs to the passed width
25712 * @param {Number} The new width
25714 setTabWidth : function(width){
25715 this.currentTabWidth = width;
25716 for(var i = 0, len = this.items.length; i < len; i++) {
25717 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25722 * Destroys this TabPanel
25723 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25725 destroy : function(removeEl){
25726 Roo.EventManager.removeResizeListener(this.onResize, this);
25727 for(var i = 0, len = this.items.length; i < len; i++){
25728 this.items[i].purgeListeners();
25730 if(removeEl === true){
25731 this.el.update("");
25738 * @class Roo.TabPanelItem
25739 * @extends Roo.util.Observable
25740 * Represents an individual item (tab plus body) in a TabPanel.
25741 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25742 * @param {String} id The id of this TabPanelItem
25743 * @param {String} text The text for the tab of this TabPanelItem
25744 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25746 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25748 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25749 * @type Roo.TabPanel
25751 this.tabPanel = tabPanel;
25753 * The id for this TabPanelItem
25758 this.disabled = false;
25762 this.loaded = false;
25763 this.closable = closable;
25766 * The body element for this TabPanelItem.
25767 * @type Roo.Element
25769 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25770 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25771 this.bodyEl.setStyle("display", "block");
25772 this.bodyEl.setStyle("zoom", "1");
25775 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25777 this.el = Roo.get(els.el, true);
25778 this.inner = Roo.get(els.inner, true);
25779 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25780 this.pnode = Roo.get(els.el.parentNode, true);
25781 this.el.on("mousedown", this.onTabMouseDown, this);
25782 this.el.on("click", this.onTabClick, this);
25785 var c = Roo.get(els.close, true);
25786 c.dom.title = this.closeText;
25787 c.addClassOnOver("close-over");
25788 c.on("click", this.closeClick, this);
25794 * Fires when this tab becomes the active tab.
25795 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25796 * @param {Roo.TabPanelItem} this
25800 * @event beforeclose
25801 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25802 * @param {Roo.TabPanelItem} this
25803 * @param {Object} e Set cancel to true on this object to cancel the close.
25805 "beforeclose": true,
25808 * Fires when this tab is closed.
25809 * @param {Roo.TabPanelItem} this
25813 * @event deactivate
25814 * Fires when this tab is no longer the active tab.
25815 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25816 * @param {Roo.TabPanelItem} this
25818 "deactivate" : true
25820 this.hidden = false;
25822 Roo.TabPanelItem.superclass.constructor.call(this);
25825 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25826 purgeListeners : function(){
25827 Roo.util.Observable.prototype.purgeListeners.call(this);
25828 this.el.removeAllListeners();
25831 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25834 this.pnode.addClass("on");
25837 this.tabPanel.stripWrap.repaint();
25839 this.fireEvent("activate", this.tabPanel, this);
25843 * Returns true if this tab is the active tab.
25844 * @return {Boolean}
25846 isActive : function(){
25847 return this.tabPanel.getActiveTab() == this;
25851 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25854 this.pnode.removeClass("on");
25856 this.fireEvent("deactivate", this.tabPanel, this);
25859 hideAction : function(){
25860 this.bodyEl.hide();
25861 this.bodyEl.setStyle("position", "absolute");
25862 this.bodyEl.setLeft("-20000px");
25863 this.bodyEl.setTop("-20000px");
25866 showAction : function(){
25867 this.bodyEl.setStyle("position", "relative");
25868 this.bodyEl.setTop("");
25869 this.bodyEl.setLeft("");
25870 this.bodyEl.show();
25874 * Set the tooltip for the tab.
25875 * @param {String} tooltip The tab's tooltip
25877 setTooltip : function(text){
25878 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25879 this.textEl.dom.qtip = text;
25880 this.textEl.dom.removeAttribute('title');
25882 this.textEl.dom.title = text;
25886 onTabClick : function(e){
25887 e.preventDefault();
25888 this.tabPanel.activate(this.id);
25891 onTabMouseDown : function(e){
25892 e.preventDefault();
25893 this.tabPanel.activate(this.id);
25896 getWidth : function(){
25897 return this.inner.getWidth();
25900 setWidth : function(width){
25901 var iwidth = width - this.pnode.getPadding("lr");
25902 this.inner.setWidth(iwidth);
25903 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25904 this.pnode.setWidth(width);
25908 * Show or hide the tab
25909 * @param {Boolean} hidden True to hide or false to show.
25911 setHidden : function(hidden){
25912 this.hidden = hidden;
25913 this.pnode.setStyle("display", hidden ? "none" : "");
25917 * Returns true if this tab is "hidden"
25918 * @return {Boolean}
25920 isHidden : function(){
25921 return this.hidden;
25925 * Returns the text for this tab
25928 getText : function(){
25932 autoSize : function(){
25933 //this.el.beginMeasure();
25934 this.textEl.setWidth(1);
25935 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25936 //this.el.endMeasure();
25940 * Sets the text for the tab (Note: this also sets the tooltip text)
25941 * @param {String} text The tab's text and tooltip
25943 setText : function(text){
25945 this.textEl.update(text);
25946 this.setTooltip(text);
25947 if(!this.tabPanel.resizeTabs){
25952 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25954 activate : function(){
25955 this.tabPanel.activate(this.id);
25959 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25961 disable : function(){
25962 if(this.tabPanel.active != this){
25963 this.disabled = true;
25964 this.pnode.addClass("disabled");
25969 * Enables this TabPanelItem if it was previously disabled.
25971 enable : function(){
25972 this.disabled = false;
25973 this.pnode.removeClass("disabled");
25977 * Sets the content for this TabPanelItem.
25978 * @param {String} content The content
25979 * @param {Boolean} loadScripts true to look for and load scripts
25981 setContent : function(content, loadScripts){
25982 this.bodyEl.update(content, loadScripts);
25986 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25987 * @return {Roo.UpdateManager} The UpdateManager
25989 getUpdateManager : function(){
25990 return this.bodyEl.getUpdateManager();
25994 * Set a URL to be used to load the content for this TabPanelItem.
25995 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25996 * @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)
25997 * @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)
25998 * @return {Roo.UpdateManager} The UpdateManager
26000 setUrl : function(url, params, loadOnce){
26001 if(this.refreshDelegate){
26002 this.un('activate', this.refreshDelegate);
26004 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26005 this.on("activate", this.refreshDelegate);
26006 return this.bodyEl.getUpdateManager();
26010 _handleRefresh : function(url, params, loadOnce){
26011 if(!loadOnce || !this.loaded){
26012 var updater = this.bodyEl.getUpdateManager();
26013 updater.update(url, params, this._setLoaded.createDelegate(this));
26018 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26019 * Will fail silently if the setUrl method has not been called.
26020 * This does not activate the panel, just updates its content.
26022 refresh : function(){
26023 if(this.refreshDelegate){
26024 this.loaded = false;
26025 this.refreshDelegate();
26030 _setLoaded : function(){
26031 this.loaded = true;
26035 closeClick : function(e){
26038 this.fireEvent("beforeclose", this, o);
26039 if(o.cancel !== true){
26040 this.tabPanel.removeTab(this.id);
26044 * The text displayed in the tooltip for the close icon.
26047 closeText : "Close this tab"
26051 Roo.TabPanel.prototype.createStrip = function(container){
26052 var strip = document.createElement("div");
26053 strip.className = "x-tabs-wrap";
26054 container.appendChild(strip);
26058 Roo.TabPanel.prototype.createStripList = function(strip){
26059 // div wrapper for retard IE
26060 // returns the "tr" element.
26061 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26062 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26063 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26064 return strip.firstChild.firstChild.firstChild.firstChild;
26067 Roo.TabPanel.prototype.createBody = function(container){
26068 var body = document.createElement("div");
26069 Roo.id(body, "tab-body");
26070 Roo.fly(body).addClass("x-tabs-body");
26071 container.appendChild(body);
26075 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26076 var body = Roo.getDom(id);
26078 body = document.createElement("div");
26081 Roo.fly(body).addClass("x-tabs-item-body");
26082 bodyEl.insertBefore(body, bodyEl.firstChild);
26086 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26087 var td = document.createElement("td");
26088 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26089 //stripEl.appendChild(td);
26091 td.className = "x-tabs-closable";
26092 if(!this.closeTpl){
26093 this.closeTpl = new Roo.Template(
26094 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26095 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26096 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26099 var el = this.closeTpl.overwrite(td, {"text": text});
26100 var close = el.getElementsByTagName("div")[0];
26101 var inner = el.getElementsByTagName("em")[0];
26102 return {"el": el, "close": close, "inner": inner};
26105 this.tabTpl = new Roo.Template(
26106 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26107 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26110 var el = this.tabTpl.overwrite(td, {"text": text});
26111 var inner = el.getElementsByTagName("em")[0];
26112 return {"el": el, "inner": inner};
26116 * Ext JS Library 1.1.1
26117 * Copyright(c) 2006-2007, Ext JS, LLC.
26119 * Originally Released Under LGPL - original licence link has changed is not relivant.
26122 * <script type="text/javascript">
26126 * @class Roo.Button
26127 * @extends Roo.util.Observable
26128 * Simple Button class
26129 * @cfg {String} text The button text
26130 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26131 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26132 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26133 * @cfg {Object} scope The scope of the handler
26134 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26135 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26136 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26137 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26138 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26139 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26140 applies if enableToggle = true)
26141 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26142 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26143 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26145 * Create a new button
26146 * @param {Object} config The config object
26148 Roo.Button = function(renderTo, config)
26152 renderTo = config.renderTo || false;
26155 Roo.apply(this, config);
26159 * Fires when this button is clicked
26160 * @param {Button} this
26161 * @param {EventObject} e The click event
26166 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26167 * @param {Button} this
26168 * @param {Boolean} pressed
26173 * Fires when the mouse hovers over the button
26174 * @param {Button} this
26175 * @param {Event} e The event object
26177 'mouseover' : true,
26180 * Fires when the mouse exits the button
26181 * @param {Button} this
26182 * @param {Event} e The event object
26187 * Fires when the button is rendered
26188 * @param {Button} this
26193 this.menu = Roo.menu.MenuMgr.get(this.menu);
26195 // register listeners first!! - so render can be captured..
26196 Roo.util.Observable.call(this);
26198 this.render(renderTo);
26204 Roo.extend(Roo.Button, Roo.util.Observable, {
26210 * Read-only. True if this button is hidden
26215 * Read-only. True if this button is disabled
26220 * Read-only. True if this button is pressed (only if enableToggle = true)
26226 * @cfg {Number} tabIndex
26227 * The DOM tabIndex for this button (defaults to undefined)
26229 tabIndex : undefined,
26232 * @cfg {Boolean} enableToggle
26233 * True to enable pressed/not pressed toggling (defaults to false)
26235 enableToggle: false,
26237 * @cfg {Mixed} menu
26238 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26242 * @cfg {String} menuAlign
26243 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26245 menuAlign : "tl-bl?",
26248 * @cfg {String} iconCls
26249 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26251 iconCls : undefined,
26253 * @cfg {String} type
26254 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26259 menuClassTarget: 'tr',
26262 * @cfg {String} clickEvent
26263 * The type of event to map to the button's event handler (defaults to 'click')
26265 clickEvent : 'click',
26268 * @cfg {Boolean} handleMouseEvents
26269 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26271 handleMouseEvents : true,
26274 * @cfg {String} tooltipType
26275 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26277 tooltipType : 'qtip',
26280 * @cfg {String} cls
26281 * A CSS class to apply to the button's main element.
26285 * @cfg {Roo.Template} template (Optional)
26286 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26287 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26288 * require code modifications if required elements (e.g. a button) aren't present.
26292 render : function(renderTo){
26294 if(this.hideParent){
26295 this.parentEl = Roo.get(renderTo);
26297 if(!this.dhconfig){
26298 if(!this.template){
26299 if(!Roo.Button.buttonTemplate){
26300 // hideous table template
26301 Roo.Button.buttonTemplate = new Roo.Template(
26302 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26303 '<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>',
26304 "</tr></tbody></table>");
26306 this.template = Roo.Button.buttonTemplate;
26308 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26309 var btnEl = btn.child("button:first");
26310 btnEl.on('focus', this.onFocus, this);
26311 btnEl.on('blur', this.onBlur, this);
26313 btn.addClass(this.cls);
26316 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26319 btnEl.addClass(this.iconCls);
26321 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26324 if(this.tabIndex !== undefined){
26325 btnEl.dom.tabIndex = this.tabIndex;
26328 if(typeof this.tooltip == 'object'){
26329 Roo.QuickTips.tips(Roo.apply({
26333 btnEl.dom[this.tooltipType] = this.tooltip;
26337 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26341 this.el.dom.id = this.el.id = this.id;
26344 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26345 this.menu.on("show", this.onMenuShow, this);
26346 this.menu.on("hide", this.onMenuHide, this);
26348 btn.addClass("x-btn");
26349 if(Roo.isIE && !Roo.isIE7){
26350 this.autoWidth.defer(1, this);
26354 if(this.handleMouseEvents){
26355 btn.on("mouseover", this.onMouseOver, this);
26356 btn.on("mouseout", this.onMouseOut, this);
26357 btn.on("mousedown", this.onMouseDown, this);
26359 btn.on(this.clickEvent, this.onClick, this);
26360 //btn.on("mouseup", this.onMouseUp, this);
26367 Roo.ButtonToggleMgr.register(this);
26369 this.el.addClass("x-btn-pressed");
26372 var repeater = new Roo.util.ClickRepeater(btn,
26373 typeof this.repeat == "object" ? this.repeat : {}
26375 repeater.on("click", this.onClick, this);
26378 this.fireEvent('render', this);
26382 * Returns the button's underlying element
26383 * @return {Roo.Element} The element
26385 getEl : function(){
26390 * Destroys this Button and removes any listeners.
26392 destroy : function(){
26393 Roo.ButtonToggleMgr.unregister(this);
26394 this.el.removeAllListeners();
26395 this.purgeListeners();
26400 autoWidth : function(){
26402 this.el.setWidth("auto");
26403 if(Roo.isIE7 && Roo.isStrict){
26404 var ib = this.el.child('button');
26405 if(ib && ib.getWidth() > 20){
26407 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26412 this.el.beginMeasure();
26414 if(this.el.getWidth() < this.minWidth){
26415 this.el.setWidth(this.minWidth);
26418 this.el.endMeasure();
26425 * Assigns this button's click handler
26426 * @param {Function} handler The function to call when the button is clicked
26427 * @param {Object} scope (optional) Scope for the function passed in
26429 setHandler : function(handler, scope){
26430 this.handler = handler;
26431 this.scope = scope;
26435 * Sets this button's text
26436 * @param {String} text The button text
26438 setText : function(text){
26441 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26447 * Gets the text for this button
26448 * @return {String} The button text
26450 getText : function(){
26458 this.hidden = false;
26460 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26468 this.hidden = true;
26470 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26475 * Convenience function for boolean show/hide
26476 * @param {Boolean} visible True to show, false to hide
26478 setVisible: function(visible){
26487 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26488 * @param {Boolean} state (optional) Force a particular state
26490 toggle : function(state){
26491 state = state === undefined ? !this.pressed : state;
26492 if(state != this.pressed){
26494 this.el.addClass("x-btn-pressed");
26495 this.pressed = true;
26496 this.fireEvent("toggle", this, true);
26498 this.el.removeClass("x-btn-pressed");
26499 this.pressed = false;
26500 this.fireEvent("toggle", this, false);
26502 if(this.toggleHandler){
26503 this.toggleHandler.call(this.scope || this, this, state);
26511 focus : function(){
26512 this.el.child('button:first').focus();
26516 * Disable this button
26518 disable : function(){
26520 this.el.addClass("x-btn-disabled");
26522 this.disabled = true;
26526 * Enable this button
26528 enable : function(){
26530 this.el.removeClass("x-btn-disabled");
26532 this.disabled = false;
26536 * Convenience function for boolean enable/disable
26537 * @param {Boolean} enabled True to enable, false to disable
26539 setDisabled : function(v){
26540 this[v !== true ? "enable" : "disable"]();
26544 onClick : function(e){
26546 e.preventDefault();
26551 if(!this.disabled){
26552 if(this.enableToggle){
26555 if(this.menu && !this.menu.isVisible()){
26556 this.menu.show(this.el, this.menuAlign);
26558 this.fireEvent("click", this, e);
26560 this.el.removeClass("x-btn-over");
26561 this.handler.call(this.scope || this, this, e);
26566 onMouseOver : function(e){
26567 if(!this.disabled){
26568 this.el.addClass("x-btn-over");
26569 this.fireEvent('mouseover', this, e);
26573 onMouseOut : function(e){
26574 if(!e.within(this.el, true)){
26575 this.el.removeClass("x-btn-over");
26576 this.fireEvent('mouseout', this, e);
26580 onFocus : function(e){
26581 if(!this.disabled){
26582 this.el.addClass("x-btn-focus");
26586 onBlur : function(e){
26587 this.el.removeClass("x-btn-focus");
26590 onMouseDown : function(e){
26591 if(!this.disabled && e.button == 0){
26592 this.el.addClass("x-btn-click");
26593 Roo.get(document).on('mouseup', this.onMouseUp, this);
26597 onMouseUp : function(e){
26599 this.el.removeClass("x-btn-click");
26600 Roo.get(document).un('mouseup', this.onMouseUp, this);
26604 onMenuShow : function(e){
26605 this.el.addClass("x-btn-menu-active");
26608 onMenuHide : function(e){
26609 this.el.removeClass("x-btn-menu-active");
26613 // Private utility class used by Button
26614 Roo.ButtonToggleMgr = function(){
26617 function toggleGroup(btn, state){
26619 var g = groups[btn.toggleGroup];
26620 for(var i = 0, l = g.length; i < l; i++){
26622 g[i].toggle(false);
26629 register : function(btn){
26630 if(!btn.toggleGroup){
26633 var g = groups[btn.toggleGroup];
26635 g = groups[btn.toggleGroup] = [];
26638 btn.on("toggle", toggleGroup);
26641 unregister : function(btn){
26642 if(!btn.toggleGroup){
26645 var g = groups[btn.toggleGroup];
26648 btn.un("toggle", toggleGroup);
26654 * Ext JS Library 1.1.1
26655 * Copyright(c) 2006-2007, Ext JS, LLC.
26657 * Originally Released Under LGPL - original licence link has changed is not relivant.
26660 * <script type="text/javascript">
26664 * @class Roo.SplitButton
26665 * @extends Roo.Button
26666 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26667 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26668 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26669 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26670 * @cfg {String} arrowTooltip The title attribute of the arrow
26672 * Create a new menu button
26673 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26674 * @param {Object} config The config object
26676 Roo.SplitButton = function(renderTo, config){
26677 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26679 * @event arrowclick
26680 * Fires when this button's arrow is clicked
26681 * @param {SplitButton} this
26682 * @param {EventObject} e The click event
26684 this.addEvents({"arrowclick":true});
26687 Roo.extend(Roo.SplitButton, Roo.Button, {
26688 render : function(renderTo){
26689 // this is one sweet looking template!
26690 var tpl = new Roo.Template(
26691 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26692 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26693 '<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>',
26694 "</tbody></table></td><td>",
26695 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26696 '<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>',
26697 "</tbody></table></td></tr></table>"
26699 var btn = tpl.append(renderTo, [this.text, this.type], true);
26700 var btnEl = btn.child("button");
26702 btn.addClass(this.cls);
26705 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26708 btnEl.addClass(this.iconCls);
26710 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26714 if(this.handleMouseEvents){
26715 btn.on("mouseover", this.onMouseOver, this);
26716 btn.on("mouseout", this.onMouseOut, this);
26717 btn.on("mousedown", this.onMouseDown, this);
26718 btn.on("mouseup", this.onMouseUp, this);
26720 btn.on(this.clickEvent, this.onClick, this);
26722 if(typeof this.tooltip == 'object'){
26723 Roo.QuickTips.tips(Roo.apply({
26727 btnEl.dom[this.tooltipType] = this.tooltip;
26730 if(this.arrowTooltip){
26731 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26740 this.el.addClass("x-btn-pressed");
26742 if(Roo.isIE && !Roo.isIE7){
26743 this.autoWidth.defer(1, this);
26748 this.menu.on("show", this.onMenuShow, this);
26749 this.menu.on("hide", this.onMenuHide, this);
26751 this.fireEvent('render', this);
26755 autoWidth : function(){
26757 var tbl = this.el.child("table:first");
26758 var tbl2 = this.el.child("table:last");
26759 this.el.setWidth("auto");
26760 tbl.setWidth("auto");
26761 if(Roo.isIE7 && Roo.isStrict){
26762 var ib = this.el.child('button:first');
26763 if(ib && ib.getWidth() > 20){
26765 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26770 this.el.beginMeasure();
26772 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26773 tbl.setWidth(this.minWidth-tbl2.getWidth());
26776 this.el.endMeasure();
26779 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26783 * Sets this button's click handler
26784 * @param {Function} handler The function to call when the button is clicked
26785 * @param {Object} scope (optional) Scope for the function passed above
26787 setHandler : function(handler, scope){
26788 this.handler = handler;
26789 this.scope = scope;
26793 * Sets this button's arrow click handler
26794 * @param {Function} handler The function to call when the arrow is clicked
26795 * @param {Object} scope (optional) Scope for the function passed above
26797 setArrowHandler : function(handler, scope){
26798 this.arrowHandler = handler;
26799 this.scope = scope;
26805 focus : function(){
26807 this.el.child("button:first").focus();
26812 onClick : function(e){
26813 e.preventDefault();
26814 if(!this.disabled){
26815 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26816 if(this.menu && !this.menu.isVisible()){
26817 this.menu.show(this.el, this.menuAlign);
26819 this.fireEvent("arrowclick", this, e);
26820 if(this.arrowHandler){
26821 this.arrowHandler.call(this.scope || this, this, e);
26824 this.fireEvent("click", this, e);
26826 this.handler.call(this.scope || this, this, e);
26832 onMouseDown : function(e){
26833 if(!this.disabled){
26834 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26838 onMouseUp : function(e){
26839 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26844 // backwards compat
26845 Roo.MenuButton = Roo.SplitButton;/*
26847 * Ext JS Library 1.1.1
26848 * Copyright(c) 2006-2007, Ext JS, LLC.
26850 * Originally Released Under LGPL - original licence link has changed is not relivant.
26853 * <script type="text/javascript">
26857 * @class Roo.Toolbar
26858 * Basic Toolbar class.
26860 * Creates a new Toolbar
26861 * @param {Object} container The config object
26863 Roo.Toolbar = function(container, buttons, config)
26865 /// old consturctor format still supported..
26866 if(container instanceof Array){ // omit the container for later rendering
26867 buttons = container;
26871 if (typeof(container) == 'object' && container.xtype) {
26872 config = container;
26873 container = config.container;
26874 buttons = config.buttons || []; // not really - use items!!
26877 if (config && config.items) {
26878 xitems = config.items;
26879 delete config.items;
26881 Roo.apply(this, config);
26882 this.buttons = buttons;
26885 this.render(container);
26887 this.xitems = xitems;
26888 Roo.each(xitems, function(b) {
26894 Roo.Toolbar.prototype = {
26896 * @cfg {Array} items
26897 * array of button configs or elements to add (will be converted to a MixedCollection)
26901 * @cfg {String/HTMLElement/Element} container
26902 * The id or element that will contain the toolbar
26905 render : function(ct){
26906 this.el = Roo.get(ct);
26908 this.el.addClass(this.cls);
26910 // using a table allows for vertical alignment
26911 // 100% width is needed by Safari...
26912 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26913 this.tr = this.el.child("tr", true);
26915 this.items = new Roo.util.MixedCollection(false, function(o){
26916 return o.id || ("item" + (++autoId));
26919 this.add.apply(this, this.buttons);
26920 delete this.buttons;
26925 * Adds element(s) to the toolbar -- this function takes a variable number of
26926 * arguments of mixed type and adds them to the toolbar.
26927 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26929 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26930 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26931 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26932 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26933 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26934 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26935 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26936 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26937 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26939 * @param {Mixed} arg2
26940 * @param {Mixed} etc.
26943 var a = arguments, l = a.length;
26944 for(var i = 0; i < l; i++){
26949 _add : function(el) {
26952 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26955 if (el.applyTo){ // some kind of form field
26956 return this.addField(el);
26958 if (el.render){ // some kind of Toolbar.Item
26959 return this.addItem(el);
26961 if (typeof el == "string"){ // string
26962 if(el == "separator" || el == "-"){
26963 return this.addSeparator();
26966 return this.addSpacer();
26969 return this.addFill();
26971 return this.addText(el);
26974 if(el.tagName){ // element
26975 return this.addElement(el);
26977 if(typeof el == "object"){ // must be button config?
26978 return this.addButton(el);
26980 // and now what?!?!
26986 * Add an Xtype element
26987 * @param {Object} xtype Xtype Object
26988 * @return {Object} created Object
26990 addxtype : function(e){
26991 return this.add(e);
26995 * Returns the Element for this toolbar.
26996 * @return {Roo.Element}
26998 getEl : function(){
27004 * @return {Roo.Toolbar.Item} The separator item
27006 addSeparator : function(){
27007 return this.addItem(new Roo.Toolbar.Separator());
27011 * Adds a spacer element
27012 * @return {Roo.Toolbar.Spacer} The spacer item
27014 addSpacer : function(){
27015 return this.addItem(new Roo.Toolbar.Spacer());
27019 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27020 * @return {Roo.Toolbar.Fill} The fill item
27022 addFill : function(){
27023 return this.addItem(new Roo.Toolbar.Fill());
27027 * Adds any standard HTML element to the toolbar
27028 * @param {String/HTMLElement/Element} el The element or id of the element to add
27029 * @return {Roo.Toolbar.Item} The element's item
27031 addElement : function(el){
27032 return this.addItem(new Roo.Toolbar.Item(el));
27035 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27036 * @type Roo.util.MixedCollection
27041 * Adds any Toolbar.Item or subclass
27042 * @param {Roo.Toolbar.Item} item
27043 * @return {Roo.Toolbar.Item} The item
27045 addItem : function(item){
27046 var td = this.nextBlock();
27048 this.items.add(item);
27053 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27054 * @param {Object/Array} config A button config or array of configs
27055 * @return {Roo.Toolbar.Button/Array}
27057 addButton : function(config){
27058 if(config instanceof Array){
27060 for(var i = 0, len = config.length; i < len; i++) {
27061 buttons.push(this.addButton(config[i]));
27066 if(!(config instanceof Roo.Toolbar.Button)){
27068 new Roo.Toolbar.SplitButton(config) :
27069 new Roo.Toolbar.Button(config);
27071 var td = this.nextBlock();
27078 * Adds text to the toolbar
27079 * @param {String} text The text to add
27080 * @return {Roo.Toolbar.Item} The element's item
27082 addText : function(text){
27083 return this.addItem(new Roo.Toolbar.TextItem(text));
27087 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27088 * @param {Number} index The index where the item is to be inserted
27089 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27090 * @return {Roo.Toolbar.Button/Item}
27092 insertButton : function(index, item){
27093 if(item instanceof Array){
27095 for(var i = 0, len = item.length; i < len; i++) {
27096 buttons.push(this.insertButton(index + i, item[i]));
27100 if (!(item instanceof Roo.Toolbar.Button)){
27101 item = new Roo.Toolbar.Button(item);
27103 var td = document.createElement("td");
27104 this.tr.insertBefore(td, this.tr.childNodes[index]);
27106 this.items.insert(index, item);
27111 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27112 * @param {Object} config
27113 * @return {Roo.Toolbar.Item} The element's item
27115 addDom : function(config, returnEl){
27116 var td = this.nextBlock();
27117 Roo.DomHelper.overwrite(td, config);
27118 var ti = new Roo.Toolbar.Item(td.firstChild);
27120 this.items.add(ti);
27125 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27126 * @type Roo.util.MixedCollection
27131 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27132 * Note: the field should not have been rendered yet. For a field that has already been
27133 * rendered, use {@link #addElement}.
27134 * @param {Roo.form.Field} field
27135 * @return {Roo.ToolbarItem}
27139 addField : function(field) {
27140 if (!this.fields) {
27142 this.fields = new Roo.util.MixedCollection(false, function(o){
27143 return o.id || ("item" + (++autoId));
27148 var td = this.nextBlock();
27150 var ti = new Roo.Toolbar.Item(td.firstChild);
27152 this.items.add(ti);
27153 this.fields.add(field);
27164 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27165 this.el.child('div').hide();
27173 this.el.child('div').show();
27177 nextBlock : function(){
27178 var td = document.createElement("td");
27179 this.tr.appendChild(td);
27184 destroy : function(){
27185 if(this.items){ // rendered?
27186 Roo.destroy.apply(Roo, this.items.items);
27188 if(this.fields){ // rendered?
27189 Roo.destroy.apply(Roo, this.fields.items);
27191 Roo.Element.uncache(this.el, this.tr);
27196 * @class Roo.Toolbar.Item
27197 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27199 * Creates a new Item
27200 * @param {HTMLElement} el
27202 Roo.Toolbar.Item = function(el){
27203 this.el = Roo.getDom(el);
27204 this.id = Roo.id(this.el);
27205 this.hidden = false;
27208 Roo.Toolbar.Item.prototype = {
27211 * Get this item's HTML Element
27212 * @return {HTMLElement}
27214 getEl : function(){
27219 render : function(td){
27221 td.appendChild(this.el);
27225 * Removes and destroys this item.
27227 destroy : function(){
27228 this.td.parentNode.removeChild(this.td);
27235 this.hidden = false;
27236 this.td.style.display = "";
27243 this.hidden = true;
27244 this.td.style.display = "none";
27248 * Convenience function for boolean show/hide.
27249 * @param {Boolean} visible true to show/false to hide
27251 setVisible: function(visible){
27260 * Try to focus this item.
27262 focus : function(){
27263 Roo.fly(this.el).focus();
27267 * Disables this item.
27269 disable : function(){
27270 Roo.fly(this.td).addClass("x-item-disabled");
27271 this.disabled = true;
27272 this.el.disabled = true;
27276 * Enables this item.
27278 enable : function(){
27279 Roo.fly(this.td).removeClass("x-item-disabled");
27280 this.disabled = false;
27281 this.el.disabled = false;
27287 * @class Roo.Toolbar.Separator
27288 * @extends Roo.Toolbar.Item
27289 * A simple toolbar separator class
27291 * Creates a new Separator
27293 Roo.Toolbar.Separator = function(){
27294 var s = document.createElement("span");
27295 s.className = "ytb-sep";
27296 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27298 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27299 enable:Roo.emptyFn,
27300 disable:Roo.emptyFn,
27305 * @class Roo.Toolbar.Spacer
27306 * @extends Roo.Toolbar.Item
27307 * A simple element that adds extra horizontal space to a toolbar.
27309 * Creates a new Spacer
27311 Roo.Toolbar.Spacer = function(){
27312 var s = document.createElement("div");
27313 s.className = "ytb-spacer";
27314 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27316 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27317 enable:Roo.emptyFn,
27318 disable:Roo.emptyFn,
27323 * @class Roo.Toolbar.Fill
27324 * @extends Roo.Toolbar.Spacer
27325 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27327 * Creates a new Spacer
27329 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27331 render : function(td){
27332 td.style.width = '100%';
27333 Roo.Toolbar.Fill.superclass.render.call(this, td);
27338 * @class Roo.Toolbar.TextItem
27339 * @extends Roo.Toolbar.Item
27340 * A simple class that renders text directly into a toolbar.
27342 * Creates a new TextItem
27343 * @param {String} text
27345 Roo.Toolbar.TextItem = function(text){
27346 if (typeof(text) == 'object') {
27349 var s = document.createElement("span");
27350 s.className = "ytb-text";
27351 s.innerHTML = text;
27352 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27354 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27355 enable:Roo.emptyFn,
27356 disable:Roo.emptyFn,
27361 * @class Roo.Toolbar.Button
27362 * @extends Roo.Button
27363 * A button that renders into a toolbar.
27365 * Creates a new Button
27366 * @param {Object} config A standard {@link Roo.Button} config object
27368 Roo.Toolbar.Button = function(config){
27369 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27371 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27372 render : function(td){
27374 Roo.Toolbar.Button.superclass.render.call(this, td);
27378 * Removes and destroys this button
27380 destroy : function(){
27381 Roo.Toolbar.Button.superclass.destroy.call(this);
27382 this.td.parentNode.removeChild(this.td);
27386 * Shows this button
27389 this.hidden = false;
27390 this.td.style.display = "";
27394 * Hides this button
27397 this.hidden = true;
27398 this.td.style.display = "none";
27402 * Disables this item
27404 disable : function(){
27405 Roo.fly(this.td).addClass("x-item-disabled");
27406 this.disabled = true;
27410 * Enables this item
27412 enable : function(){
27413 Roo.fly(this.td).removeClass("x-item-disabled");
27414 this.disabled = false;
27417 // backwards compat
27418 Roo.ToolbarButton = Roo.Toolbar.Button;
27421 * @class Roo.Toolbar.SplitButton
27422 * @extends Roo.SplitButton
27423 * A menu button that renders into a toolbar.
27425 * Creates a new SplitButton
27426 * @param {Object} config A standard {@link Roo.SplitButton} config object
27428 Roo.Toolbar.SplitButton = function(config){
27429 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27431 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27432 render : function(td){
27434 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27438 * Removes and destroys this button
27440 destroy : function(){
27441 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27442 this.td.parentNode.removeChild(this.td);
27446 * Shows this button
27449 this.hidden = false;
27450 this.td.style.display = "";
27454 * Hides this button
27457 this.hidden = true;
27458 this.td.style.display = "none";
27462 // backwards compat
27463 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27465 * Ext JS Library 1.1.1
27466 * Copyright(c) 2006-2007, Ext JS, LLC.
27468 * Originally Released Under LGPL - original licence link has changed is not relivant.
27471 * <script type="text/javascript">
27475 * @class Roo.PagingToolbar
27476 * @extends Roo.Toolbar
27477 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27479 * Create a new PagingToolbar
27480 * @param {Object} config The config object
27482 Roo.PagingToolbar = function(el, ds, config)
27484 // old args format still supported... - xtype is prefered..
27485 if (typeof(el) == 'object' && el.xtype) {
27486 // created from xtype...
27488 ds = el.dataSource;
27489 el = config.container;
27492 if (config.items) {
27493 items = config.items;
27497 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27500 this.renderButtons(this.el);
27503 // supprot items array.
27505 Roo.each(items, function(e) {
27506 this.add(Roo.factory(e));
27511 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27513 * @cfg {Roo.data.Store} dataSource
27514 * The underlying data store providing the paged data
27517 * @cfg {String/HTMLElement/Element} container
27518 * container The id or element that will contain the toolbar
27521 * @cfg {Boolean} displayInfo
27522 * True to display the displayMsg (defaults to false)
27525 * @cfg {Number} pageSize
27526 * The number of records to display per page (defaults to 20)
27530 * @cfg {String} displayMsg
27531 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27533 displayMsg : 'Displaying {0} - {1} of {2}',
27535 * @cfg {String} emptyMsg
27536 * The message to display when no records are found (defaults to "No data to display")
27538 emptyMsg : 'No data to display',
27540 * Customizable piece of the default paging text (defaults to "Page")
27543 beforePageText : "Page",
27545 * Customizable piece of the default paging text (defaults to "of %0")
27548 afterPageText : "of {0}",
27550 * Customizable piece of the default paging text (defaults to "First Page")
27553 firstText : "First Page",
27555 * Customizable piece of the default paging text (defaults to "Previous Page")
27558 prevText : "Previous Page",
27560 * Customizable piece of the default paging text (defaults to "Next Page")
27563 nextText : "Next Page",
27565 * Customizable piece of the default paging text (defaults to "Last Page")
27568 lastText : "Last Page",
27570 * Customizable piece of the default paging text (defaults to "Refresh")
27573 refreshText : "Refresh",
27576 renderButtons : function(el){
27577 Roo.PagingToolbar.superclass.render.call(this, el);
27578 this.first = this.addButton({
27579 tooltip: this.firstText,
27580 cls: "x-btn-icon x-grid-page-first",
27582 handler: this.onClick.createDelegate(this, ["first"])
27584 this.prev = this.addButton({
27585 tooltip: this.prevText,
27586 cls: "x-btn-icon x-grid-page-prev",
27588 handler: this.onClick.createDelegate(this, ["prev"])
27590 //this.addSeparator();
27591 this.add(this.beforePageText);
27592 this.field = Roo.get(this.addDom({
27597 cls: "x-grid-page-number"
27599 this.field.on("keydown", this.onPagingKeydown, this);
27600 this.field.on("focus", function(){this.dom.select();});
27601 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27602 this.field.setHeight(18);
27603 //this.addSeparator();
27604 this.next = this.addButton({
27605 tooltip: this.nextText,
27606 cls: "x-btn-icon x-grid-page-next",
27608 handler: this.onClick.createDelegate(this, ["next"])
27610 this.last = this.addButton({
27611 tooltip: this.lastText,
27612 cls: "x-btn-icon x-grid-page-last",
27614 handler: this.onClick.createDelegate(this, ["last"])
27616 //this.addSeparator();
27617 this.loading = this.addButton({
27618 tooltip: this.refreshText,
27619 cls: "x-btn-icon x-grid-loading",
27620 handler: this.onClick.createDelegate(this, ["refresh"])
27623 if(this.displayInfo){
27624 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27629 updateInfo : function(){
27630 if(this.displayEl){
27631 var count = this.ds.getCount();
27632 var msg = count == 0 ?
27636 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27638 this.displayEl.update(msg);
27643 onLoad : function(ds, r, o){
27644 this.cursor = o.params ? o.params.start : 0;
27645 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27647 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27648 this.field.dom.value = ap;
27649 this.first.setDisabled(ap == 1);
27650 this.prev.setDisabled(ap == 1);
27651 this.next.setDisabled(ap == ps);
27652 this.last.setDisabled(ap == ps);
27653 this.loading.enable();
27658 getPageData : function(){
27659 var total = this.ds.getTotalCount();
27662 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27663 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27668 onLoadError : function(){
27669 this.loading.enable();
27673 onPagingKeydown : function(e){
27674 var k = e.getKey();
27675 var d = this.getPageData();
27677 var v = this.field.dom.value, pageNum;
27678 if(!v || isNaN(pageNum = parseInt(v, 10))){
27679 this.field.dom.value = d.activePage;
27682 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27683 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27686 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))
27688 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27689 this.field.dom.value = pageNum;
27690 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27693 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27695 var v = this.field.dom.value, pageNum;
27696 var increment = (e.shiftKey) ? 10 : 1;
27697 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27699 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27700 this.field.dom.value = d.activePage;
27703 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27705 this.field.dom.value = parseInt(v, 10) + increment;
27706 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27707 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27714 beforeLoad : function(){
27716 this.loading.disable();
27721 onClick : function(which){
27725 ds.load({params:{start: 0, limit: this.pageSize}});
27728 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27731 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27734 var total = ds.getTotalCount();
27735 var extra = total % this.pageSize;
27736 var lastStart = extra ? (total - extra) : total-this.pageSize;
27737 ds.load({params:{start: lastStart, limit: this.pageSize}});
27740 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27746 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27747 * @param {Roo.data.Store} store The data store to unbind
27749 unbind : function(ds){
27750 ds.un("beforeload", this.beforeLoad, this);
27751 ds.un("load", this.onLoad, this);
27752 ds.un("loadexception", this.onLoadError, this);
27753 ds.un("remove", this.updateInfo, this);
27754 ds.un("add", this.updateInfo, this);
27755 this.ds = undefined;
27759 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27760 * @param {Roo.data.Store} store The data store to bind
27762 bind : function(ds){
27763 ds.on("beforeload", this.beforeLoad, this);
27764 ds.on("load", this.onLoad, this);
27765 ds.on("loadexception", this.onLoadError, this);
27766 ds.on("remove", this.updateInfo, this);
27767 ds.on("add", this.updateInfo, this);
27772 * Ext JS Library 1.1.1
27773 * Copyright(c) 2006-2007, Ext JS, LLC.
27775 * Originally Released Under LGPL - original licence link has changed is not relivant.
27778 * <script type="text/javascript">
27782 * @class Roo.Resizable
27783 * @extends Roo.util.Observable
27784 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27785 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27786 * 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
27787 * the element will be wrapped for you automatically.</p>
27788 * <p>Here is the list of valid resize handles:</p>
27791 ------ -------------------
27800 'hd' horizontal drag
27803 * <p>Here's an example showing the creation of a typical Resizable:</p>
27805 var resizer = new Roo.Resizable("element-id", {
27813 resizer.on("resize", myHandler);
27815 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27816 * resizer.east.setDisplayed(false);</p>
27817 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27818 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27819 * resize operation's new size (defaults to [0, 0])
27820 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27821 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27822 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27823 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27824 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27825 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27826 * @cfg {Number} width The width of the element in pixels (defaults to null)
27827 * @cfg {Number} height The height of the element in pixels (defaults to null)
27828 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27829 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27830 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27831 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27832 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27833 * in favor of the handles config option (defaults to false)
27834 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27835 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27836 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27837 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27838 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27839 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27840 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27841 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27842 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27843 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27844 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27846 * Create a new resizable component
27847 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27848 * @param {Object} config configuration options
27850 Roo.Resizable = function(el, config)
27852 this.el = Roo.get(el);
27854 if(config && config.wrap){
27855 config.resizeChild = this.el;
27856 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27857 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27858 this.el.setStyle("overflow", "hidden");
27859 this.el.setPositioning(config.resizeChild.getPositioning());
27860 config.resizeChild.clearPositioning();
27861 if(!config.width || !config.height){
27862 var csize = config.resizeChild.getSize();
27863 this.el.setSize(csize.width, csize.height);
27865 if(config.pinned && !config.adjustments){
27866 config.adjustments = "auto";
27870 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27871 this.proxy.unselectable();
27872 this.proxy.enableDisplayMode('block');
27874 Roo.apply(this, config);
27877 this.disableTrackOver = true;
27878 this.el.addClass("x-resizable-pinned");
27880 // if the element isn't positioned, make it relative
27881 var position = this.el.getStyle("position");
27882 if(position != "absolute" && position != "fixed"){
27883 this.el.setStyle("position", "relative");
27885 if(!this.handles){ // no handles passed, must be legacy style
27886 this.handles = 's,e,se';
27887 if(this.multiDirectional){
27888 this.handles += ',n,w';
27891 if(this.handles == "all"){
27892 this.handles = "n s e w ne nw se sw";
27894 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27895 var ps = Roo.Resizable.positions;
27896 for(var i = 0, len = hs.length; i < len; i++){
27897 if(hs[i] && ps[hs[i]]){
27898 var pos = ps[hs[i]];
27899 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27903 this.corner = this.southeast;
27905 // updateBox = the box can move..
27906 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27907 this.updateBox = true;
27910 this.activeHandle = null;
27912 if(this.resizeChild){
27913 if(typeof this.resizeChild == "boolean"){
27914 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27916 this.resizeChild = Roo.get(this.resizeChild, true);
27920 if(this.adjustments == "auto"){
27921 var rc = this.resizeChild;
27922 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27923 if(rc && (hw || hn)){
27924 rc.position("relative");
27925 rc.setLeft(hw ? hw.el.getWidth() : 0);
27926 rc.setTop(hn ? hn.el.getHeight() : 0);
27928 this.adjustments = [
27929 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27930 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27934 if(this.draggable){
27935 this.dd = this.dynamic ?
27936 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27937 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27943 * @event beforeresize
27944 * Fired before resize is allowed. Set enabled to false to cancel resize.
27945 * @param {Roo.Resizable} this
27946 * @param {Roo.EventObject} e The mousedown event
27948 "beforeresize" : true,
27951 * Fired after a resize.
27952 * @param {Roo.Resizable} this
27953 * @param {Number} width The new width
27954 * @param {Number} height The new height
27955 * @param {Roo.EventObject} e The mouseup event
27960 if(this.width !== null && this.height !== null){
27961 this.resizeTo(this.width, this.height);
27963 this.updateChildSize();
27966 this.el.dom.style.zoom = 1;
27968 Roo.Resizable.superclass.constructor.call(this);
27971 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27972 resizeChild : false,
27973 adjustments : [0, 0],
27983 multiDirectional : false,
27984 disableTrackOver : false,
27985 easing : 'easeOutStrong',
27986 widthIncrement : 0,
27987 heightIncrement : 0,
27991 preserveRatio : false,
27992 transparent: false,
27998 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28000 constrainTo: undefined,
28002 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28004 resizeRegion: undefined,
28008 * Perform a manual resize
28009 * @param {Number} width
28010 * @param {Number} height
28012 resizeTo : function(width, height){
28013 this.el.setSize(width, height);
28014 this.updateChildSize();
28015 this.fireEvent("resize", this, width, height, null);
28019 startSizing : function(e, handle){
28020 this.fireEvent("beforeresize", this, e);
28021 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28024 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28025 this.overlay.unselectable();
28026 this.overlay.enableDisplayMode("block");
28027 this.overlay.on("mousemove", this.onMouseMove, this);
28028 this.overlay.on("mouseup", this.onMouseUp, this);
28030 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28032 this.resizing = true;
28033 this.startBox = this.el.getBox();
28034 this.startPoint = e.getXY();
28035 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28036 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28038 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28039 this.overlay.show();
28041 if(this.constrainTo) {
28042 var ct = Roo.get(this.constrainTo);
28043 this.resizeRegion = ct.getRegion().adjust(
28044 ct.getFrameWidth('t'),
28045 ct.getFrameWidth('l'),
28046 -ct.getFrameWidth('b'),
28047 -ct.getFrameWidth('r')
28051 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28053 this.proxy.setBox(this.startBox);
28055 this.proxy.setStyle('visibility', 'visible');
28061 onMouseDown : function(handle, e){
28064 this.activeHandle = handle;
28065 this.startSizing(e, handle);
28070 onMouseUp : function(e){
28071 var size = this.resizeElement();
28072 this.resizing = false;
28074 this.overlay.hide();
28076 this.fireEvent("resize", this, size.width, size.height, e);
28080 updateChildSize : function(){
28081 if(this.resizeChild){
28083 var child = this.resizeChild;
28084 var adj = this.adjustments;
28085 if(el.dom.offsetWidth){
28086 var b = el.getSize(true);
28087 child.setSize(b.width+adj[0], b.height+adj[1]);
28089 // Second call here for IE
28090 // The first call enables instant resizing and
28091 // the second call corrects scroll bars if they
28094 setTimeout(function(){
28095 if(el.dom.offsetWidth){
28096 var b = el.getSize(true);
28097 child.setSize(b.width+adj[0], b.height+adj[1]);
28105 snap : function(value, inc, min){
28106 if(!inc || !value) return value;
28107 var newValue = value;
28108 var m = value % inc;
28111 newValue = value + (inc-m);
28113 newValue = value - m;
28116 return Math.max(min, newValue);
28120 resizeElement : function(){
28121 var box = this.proxy.getBox();
28122 if(this.updateBox){
28123 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28125 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28127 this.updateChildSize();
28135 constrain : function(v, diff, m, mx){
28138 }else if(v - diff > mx){
28145 onMouseMove : function(e){
28147 try{// try catch so if something goes wrong the user doesn't get hung
28149 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28153 //var curXY = this.startPoint;
28154 var curSize = this.curSize || this.startBox;
28155 var x = this.startBox.x, y = this.startBox.y;
28156 var ox = x, oy = y;
28157 var w = curSize.width, h = curSize.height;
28158 var ow = w, oh = h;
28159 var mw = this.minWidth, mh = this.minHeight;
28160 var mxw = this.maxWidth, mxh = this.maxHeight;
28161 var wi = this.widthIncrement;
28162 var hi = this.heightIncrement;
28164 var eventXY = e.getXY();
28165 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28166 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28168 var pos = this.activeHandle.position;
28173 w = Math.min(Math.max(mw, w), mxw);
28178 h = Math.min(Math.max(mh, h), mxh);
28183 w = Math.min(Math.max(mw, w), mxw);
28184 h = Math.min(Math.max(mh, h), mxh);
28187 diffY = this.constrain(h, diffY, mh, mxh);
28194 var adiffX = Math.abs(diffX);
28195 var sub = (adiffX % wi); // how much
28196 if (sub > (wi/2)) { // far enough to snap
28197 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28199 // remove difference..
28200 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28204 x = Math.max(this.minX, x);
28207 diffX = this.constrain(w, diffX, mw, mxw);
28213 w = Math.min(Math.max(mw, w), mxw);
28214 diffY = this.constrain(h, diffY, mh, mxh);
28219 diffX = this.constrain(w, diffX, mw, mxw);
28220 diffY = this.constrain(h, diffY, mh, mxh);
28227 diffX = this.constrain(w, diffX, mw, mxw);
28229 h = Math.min(Math.max(mh, h), mxh);
28235 var sw = this.snap(w, wi, mw);
28236 var sh = this.snap(h, hi, mh);
28237 if(sw != w || sh != h){
28260 if(this.preserveRatio){
28265 h = Math.min(Math.max(mh, h), mxh);
28270 w = Math.min(Math.max(mw, w), mxw);
28275 w = Math.min(Math.max(mw, w), mxw);
28281 w = Math.min(Math.max(mw, w), mxw);
28287 h = Math.min(Math.max(mh, h), mxh);
28295 h = Math.min(Math.max(mh, h), mxh);
28305 h = Math.min(Math.max(mh, h), mxh);
28313 if (pos == 'hdrag') {
28316 this.proxy.setBounds(x, y, w, h);
28318 this.resizeElement();
28325 handleOver : function(){
28327 this.el.addClass("x-resizable-over");
28332 handleOut : function(){
28333 if(!this.resizing){
28334 this.el.removeClass("x-resizable-over");
28339 * Returns the element this component is bound to.
28340 * @return {Roo.Element}
28342 getEl : function(){
28347 * Returns the resizeChild element (or null).
28348 * @return {Roo.Element}
28350 getResizeChild : function(){
28351 return this.resizeChild;
28355 * Destroys this resizable. If the element was wrapped and
28356 * removeEl is not true then the element remains.
28357 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28359 destroy : function(removeEl){
28360 this.proxy.remove();
28362 this.overlay.removeAllListeners();
28363 this.overlay.remove();
28365 var ps = Roo.Resizable.positions;
28367 if(typeof ps[k] != "function" && this[ps[k]]){
28368 var h = this[ps[k]];
28369 h.el.removeAllListeners();
28374 this.el.update("");
28381 // hash to map config positions to true positions
28382 Roo.Resizable.positions = {
28383 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28388 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28390 // only initialize the template if resizable is used
28391 var tpl = Roo.DomHelper.createTemplate(
28392 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28395 Roo.Resizable.Handle.prototype.tpl = tpl;
28397 this.position = pos;
28399 // show north drag fro topdra
28400 var handlepos = pos == 'hdrag' ? 'north' : pos;
28402 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28403 if (pos == 'hdrag') {
28404 this.el.setStyle('cursor', 'pointer');
28406 this.el.unselectable();
28408 this.el.setOpacity(0);
28410 this.el.on("mousedown", this.onMouseDown, this);
28411 if(!disableTrackOver){
28412 this.el.on("mouseover", this.onMouseOver, this);
28413 this.el.on("mouseout", this.onMouseOut, this);
28418 Roo.Resizable.Handle.prototype = {
28419 afterResize : function(rz){
28423 onMouseDown : function(e){
28424 this.rz.onMouseDown(this, e);
28427 onMouseOver : function(e){
28428 this.rz.handleOver(this, e);
28431 onMouseOut : function(e){
28432 this.rz.handleOut(this, e);
28436 * Ext JS Library 1.1.1
28437 * Copyright(c) 2006-2007, Ext JS, LLC.
28439 * Originally Released Under LGPL - original licence link has changed is not relivant.
28442 * <script type="text/javascript">
28446 * @class Roo.Editor
28447 * @extends Roo.Component
28448 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28450 * Create a new Editor
28451 * @param {Roo.form.Field} field The Field object (or descendant)
28452 * @param {Object} config The config object
28454 Roo.Editor = function(field, config){
28455 Roo.Editor.superclass.constructor.call(this, config);
28456 this.field = field;
28459 * @event beforestartedit
28460 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28461 * false from the handler of this event.
28462 * @param {Editor} this
28463 * @param {Roo.Element} boundEl The underlying element bound to this editor
28464 * @param {Mixed} value The field value being set
28466 "beforestartedit" : true,
28469 * Fires when this editor is displayed
28470 * @param {Roo.Element} boundEl The underlying element bound to this editor
28471 * @param {Mixed} value The starting field value
28473 "startedit" : true,
28475 * @event beforecomplete
28476 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28477 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28478 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28479 * event will not fire since no edit actually occurred.
28480 * @param {Editor} this
28481 * @param {Mixed} value The current field value
28482 * @param {Mixed} startValue The original field value
28484 "beforecomplete" : true,
28487 * Fires after editing is complete and any changed value has been written to the underlying field.
28488 * @param {Editor} this
28489 * @param {Mixed} value The current field value
28490 * @param {Mixed} startValue The original field value
28494 * @event specialkey
28495 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28496 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28497 * @param {Roo.form.Field} this
28498 * @param {Roo.EventObject} e The event object
28500 "specialkey" : true
28504 Roo.extend(Roo.Editor, Roo.Component, {
28506 * @cfg {Boolean/String} autosize
28507 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28508 * or "height" to adopt the height only (defaults to false)
28511 * @cfg {Boolean} revertInvalid
28512 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28513 * validation fails (defaults to true)
28516 * @cfg {Boolean} ignoreNoChange
28517 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28518 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28519 * will never be ignored.
28522 * @cfg {Boolean} hideEl
28523 * False to keep the bound element visible while the editor is displayed (defaults to true)
28526 * @cfg {Mixed} value
28527 * The data value of the underlying field (defaults to "")
28531 * @cfg {String} alignment
28532 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28536 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28537 * for bottom-right shadow (defaults to "frame")
28541 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28545 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28547 completeOnEnter : false,
28549 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28551 cancelOnEsc : false,
28553 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28558 onRender : function(ct, position){
28559 this.el = new Roo.Layer({
28560 shadow: this.shadow,
28566 constrain: this.constrain
28568 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28569 if(this.field.msgTarget != 'title'){
28570 this.field.msgTarget = 'qtip';
28572 this.field.render(this.el);
28574 this.field.el.dom.setAttribute('autocomplete', 'off');
28576 this.field.on("specialkey", this.onSpecialKey, this);
28577 if(this.swallowKeys){
28578 this.field.el.swallowEvent(['keydown','keypress']);
28581 this.field.on("blur", this.onBlur, this);
28582 if(this.field.grow){
28583 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28587 onSpecialKey : function(field, e)
28589 //Roo.log('editor onSpecialKey');
28590 if(this.completeOnEnter && e.getKey() == e.ENTER){
28592 this.completeEdit();
28595 // do not fire special key otherwise it might hide close the editor...
28596 if(e.getKey() == e.ENTER){
28599 if(this.cancelOnEsc && e.getKey() == e.ESC){
28603 this.fireEvent('specialkey', field, e);
28608 * Starts the editing process and shows the editor.
28609 * @param {String/HTMLElement/Element} el The element to edit
28610 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28611 * to the innerHTML of el.
28613 startEdit : function(el, value){
28615 this.completeEdit();
28617 this.boundEl = Roo.get(el);
28618 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28619 if(!this.rendered){
28620 this.render(this.parentEl || document.body);
28622 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28625 this.startValue = v;
28626 this.field.setValue(v);
28628 var sz = this.boundEl.getSize();
28629 switch(this.autoSize){
28631 this.setSize(sz.width, "");
28634 this.setSize("", sz.height);
28637 this.setSize(sz.width, sz.height);
28640 this.el.alignTo(this.boundEl, this.alignment);
28641 this.editing = true;
28643 Roo.QuickTips.disable();
28649 * Sets the height and width of this editor.
28650 * @param {Number} width The new width
28651 * @param {Number} height The new height
28653 setSize : function(w, h){
28654 this.field.setSize(w, h);
28661 * Realigns the editor to the bound field based on the current alignment config value.
28663 realign : function(){
28664 this.el.alignTo(this.boundEl, this.alignment);
28668 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28669 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28671 completeEdit : function(remainVisible){
28675 var v = this.getValue();
28676 if(this.revertInvalid !== false && !this.field.isValid()){
28677 v = this.startValue;
28678 this.cancelEdit(true);
28680 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28681 this.editing = false;
28685 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28686 this.editing = false;
28687 if(this.updateEl && this.boundEl){
28688 this.boundEl.update(v);
28690 if(remainVisible !== true){
28693 this.fireEvent("complete", this, v, this.startValue);
28698 onShow : function(){
28700 if(this.hideEl !== false){
28701 this.boundEl.hide();
28704 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28705 this.fixIEFocus = true;
28706 this.deferredFocus.defer(50, this);
28708 this.field.focus();
28710 this.fireEvent("startedit", this.boundEl, this.startValue);
28713 deferredFocus : function(){
28715 this.field.focus();
28720 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28721 * reverted to the original starting value.
28722 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28723 * cancel (defaults to false)
28725 cancelEdit : function(remainVisible){
28727 this.setValue(this.startValue);
28728 if(remainVisible !== true){
28735 onBlur : function(){
28736 if(this.allowBlur !== true && this.editing){
28737 this.completeEdit();
28742 onHide : function(){
28744 this.completeEdit();
28748 if(this.field.collapse){
28749 this.field.collapse();
28752 if(this.hideEl !== false){
28753 this.boundEl.show();
28756 Roo.QuickTips.enable();
28761 * Sets the data value of the editor
28762 * @param {Mixed} value Any valid value supported by the underlying field
28764 setValue : function(v){
28765 this.field.setValue(v);
28769 * Gets the data value of the editor
28770 * @return {Mixed} The data value
28772 getValue : function(){
28773 return this.field.getValue();
28777 * Ext JS Library 1.1.1
28778 * Copyright(c) 2006-2007, Ext JS, LLC.
28780 * Originally Released Under LGPL - original licence link has changed is not relivant.
28783 * <script type="text/javascript">
28787 * @class Roo.BasicDialog
28788 * @extends Roo.util.Observable
28789 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28791 var dlg = new Roo.BasicDialog("my-dlg", {
28800 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28801 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28802 dlg.addButton('Cancel', dlg.hide, dlg);
28805 <b>A Dialog should always be a direct child of the body element.</b>
28806 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28807 * @cfg {String} title Default text to display in the title bar (defaults to null)
28808 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28809 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28810 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28811 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28812 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28813 * (defaults to null with no animation)
28814 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28815 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28816 * property for valid values (defaults to 'all')
28817 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28818 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28819 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28820 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28821 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28822 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28823 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28824 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28825 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28826 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28827 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28828 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28829 * draggable = true (defaults to false)
28830 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28831 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28832 * shadow (defaults to false)
28833 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28834 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28835 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28836 * @cfg {Array} buttons Array of buttons
28837 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28839 * Create a new BasicDialog.
28840 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28841 * @param {Object} config Configuration options
28843 Roo.BasicDialog = function(el, config){
28844 this.el = Roo.get(el);
28845 var dh = Roo.DomHelper;
28846 if(!this.el && config && config.autoCreate){
28847 if(typeof config.autoCreate == "object"){
28848 if(!config.autoCreate.id){
28849 config.autoCreate.id = el;
28851 this.el = dh.append(document.body,
28852 config.autoCreate, true);
28854 this.el = dh.append(document.body,
28855 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28859 el.setDisplayed(true);
28860 el.hide = this.hideAction;
28862 el.addClass("x-dlg");
28864 Roo.apply(this, config);
28866 this.proxy = el.createProxy("x-dlg-proxy");
28867 this.proxy.hide = this.hideAction;
28868 this.proxy.setOpacity(.5);
28872 el.setWidth(config.width);
28875 el.setHeight(config.height);
28877 this.size = el.getSize();
28878 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28879 this.xy = [config.x,config.y];
28881 this.xy = el.getCenterXY(true);
28883 /** The header element @type Roo.Element */
28884 this.header = el.child("> .x-dlg-hd");
28885 /** The body element @type Roo.Element */
28886 this.body = el.child("> .x-dlg-bd");
28887 /** The footer element @type Roo.Element */
28888 this.footer = el.child("> .x-dlg-ft");
28891 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28894 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28897 this.header.unselectable();
28899 this.header.update(this.title);
28901 // this element allows the dialog to be focused for keyboard event
28902 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28903 this.focusEl.swallowEvent("click", true);
28905 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28907 // wrap the body and footer for special rendering
28908 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28910 this.bwrap.dom.appendChild(this.footer.dom);
28913 this.bg = this.el.createChild({
28914 tag: "div", cls:"x-dlg-bg",
28915 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28917 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28920 if(this.autoScroll !== false && !this.autoTabs){
28921 this.body.setStyle("overflow", "auto");
28924 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28926 if(this.closable !== false){
28927 this.el.addClass("x-dlg-closable");
28928 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28929 this.close.on("click", this.closeClick, this);
28930 this.close.addClassOnOver("x-dlg-close-over");
28932 if(this.collapsible !== false){
28933 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28934 this.collapseBtn.on("click", this.collapseClick, this);
28935 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28936 this.header.on("dblclick", this.collapseClick, this);
28938 if(this.resizable !== false){
28939 this.el.addClass("x-dlg-resizable");
28940 this.resizer = new Roo.Resizable(el, {
28941 minWidth: this.minWidth || 80,
28942 minHeight:this.minHeight || 80,
28943 handles: this.resizeHandles || "all",
28946 this.resizer.on("beforeresize", this.beforeResize, this);
28947 this.resizer.on("resize", this.onResize, this);
28949 if(this.draggable !== false){
28950 el.addClass("x-dlg-draggable");
28951 if (!this.proxyDrag) {
28952 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28955 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28957 dd.setHandleElId(this.header.id);
28958 dd.endDrag = this.endMove.createDelegate(this);
28959 dd.startDrag = this.startMove.createDelegate(this);
28960 dd.onDrag = this.onDrag.createDelegate(this);
28965 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28966 this.mask.enableDisplayMode("block");
28968 this.el.addClass("x-dlg-modal");
28971 this.shadow = new Roo.Shadow({
28972 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28973 offset : this.shadowOffset
28976 this.shadowOffset = 0;
28978 if(Roo.useShims && this.shim !== false){
28979 this.shim = this.el.createShim();
28980 this.shim.hide = this.hideAction;
28988 if (this.buttons) {
28989 var bts= this.buttons;
28991 Roo.each(bts, function(b) {
29000 * Fires when a key is pressed
29001 * @param {Roo.BasicDialog} this
29002 * @param {Roo.EventObject} e
29007 * Fires when this dialog is moved by the user.
29008 * @param {Roo.BasicDialog} this
29009 * @param {Number} x The new page X
29010 * @param {Number} y The new page Y
29015 * Fires when this dialog is resized by the user.
29016 * @param {Roo.BasicDialog} this
29017 * @param {Number} width The new width
29018 * @param {Number} height The new height
29022 * @event beforehide
29023 * Fires before this dialog is hidden.
29024 * @param {Roo.BasicDialog} this
29026 "beforehide" : true,
29029 * Fires when this dialog is hidden.
29030 * @param {Roo.BasicDialog} this
29034 * @event beforeshow
29035 * Fires before this dialog is shown.
29036 * @param {Roo.BasicDialog} this
29038 "beforeshow" : true,
29041 * Fires when this dialog is shown.
29042 * @param {Roo.BasicDialog} this
29046 el.on("keydown", this.onKeyDown, this);
29047 el.on("mousedown", this.toFront, this);
29048 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29050 Roo.DialogManager.register(this);
29051 Roo.BasicDialog.superclass.constructor.call(this);
29054 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29055 shadowOffset: Roo.isIE ? 6 : 5,
29058 minButtonWidth: 75,
29059 defaultButton: null,
29060 buttonAlign: "right",
29065 * Sets the dialog title text
29066 * @param {String} text The title text to display
29067 * @return {Roo.BasicDialog} this
29069 setTitle : function(text){
29070 this.header.update(text);
29075 closeClick : function(){
29080 collapseClick : function(){
29081 this[this.collapsed ? "expand" : "collapse"]();
29085 * Collapses the dialog to its minimized state (only the title bar is visible).
29086 * Equivalent to the user clicking the collapse dialog button.
29088 collapse : function(){
29089 if(!this.collapsed){
29090 this.collapsed = true;
29091 this.el.addClass("x-dlg-collapsed");
29092 this.restoreHeight = this.el.getHeight();
29093 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29098 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29099 * clicking the expand dialog button.
29101 expand : function(){
29102 if(this.collapsed){
29103 this.collapsed = false;
29104 this.el.removeClass("x-dlg-collapsed");
29105 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29110 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29111 * @return {Roo.TabPanel} The tabs component
29113 initTabs : function(){
29114 var tabs = this.getTabs();
29115 while(tabs.getTab(0)){
29118 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29120 tabs.addTab(Roo.id(dom), dom.title);
29128 beforeResize : function(){
29129 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29133 onResize : function(){
29134 this.refreshSize();
29135 this.syncBodyHeight();
29136 this.adjustAssets();
29138 this.fireEvent("resize", this, this.size.width, this.size.height);
29142 onKeyDown : function(e){
29143 if(this.isVisible()){
29144 this.fireEvent("keydown", this, e);
29149 * Resizes the dialog.
29150 * @param {Number} width
29151 * @param {Number} height
29152 * @return {Roo.BasicDialog} this
29154 resizeTo : function(width, height){
29155 this.el.setSize(width, height);
29156 this.size = {width: width, height: height};
29157 this.syncBodyHeight();
29158 if(this.fixedcenter){
29161 if(this.isVisible()){
29162 this.constrainXY();
29163 this.adjustAssets();
29165 this.fireEvent("resize", this, width, height);
29171 * Resizes the dialog to fit the specified content size.
29172 * @param {Number} width
29173 * @param {Number} height
29174 * @return {Roo.BasicDialog} this
29176 setContentSize : function(w, h){
29177 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29178 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29179 //if(!this.el.isBorderBox()){
29180 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29181 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29184 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29185 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29187 this.resizeTo(w, h);
29192 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29193 * executed in response to a particular key being pressed while the dialog is active.
29194 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29195 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29196 * @param {Function} fn The function to call
29197 * @param {Object} scope (optional) The scope of the function
29198 * @return {Roo.BasicDialog} this
29200 addKeyListener : function(key, fn, scope){
29201 var keyCode, shift, ctrl, alt;
29202 if(typeof key == "object" && !(key instanceof Array)){
29203 keyCode = key["key"];
29204 shift = key["shift"];
29205 ctrl = key["ctrl"];
29210 var handler = function(dlg, e){
29211 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29212 var k = e.getKey();
29213 if(keyCode instanceof Array){
29214 for(var i = 0, len = keyCode.length; i < len; i++){
29215 if(keyCode[i] == k){
29216 fn.call(scope || window, dlg, k, e);
29222 fn.call(scope || window, dlg, k, e);
29227 this.on("keydown", handler);
29232 * Returns the TabPanel component (creates it if it doesn't exist).
29233 * Note: If you wish to simply check for the existence of tabs without creating them,
29234 * check for a null 'tabs' property.
29235 * @return {Roo.TabPanel} The tabs component
29237 getTabs : function(){
29239 this.el.addClass("x-dlg-auto-tabs");
29240 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29241 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29247 * Adds a button to the footer section of the dialog.
29248 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29249 * object or a valid Roo.DomHelper element config
29250 * @param {Function} handler The function called when the button is clicked
29251 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29252 * @return {Roo.Button} The new button
29254 addButton : function(config, handler, scope){
29255 var dh = Roo.DomHelper;
29257 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29259 if(!this.btnContainer){
29260 var tb = this.footer.createChild({
29262 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29263 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29265 this.btnContainer = tb.firstChild.firstChild.firstChild;
29270 minWidth: this.minButtonWidth,
29273 if(typeof config == "string"){
29274 bconfig.text = config;
29277 bconfig.dhconfig = config;
29279 Roo.apply(bconfig, config);
29283 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29284 bconfig.position = Math.max(0, bconfig.position);
29285 fc = this.btnContainer.childNodes[bconfig.position];
29288 var btn = new Roo.Button(
29290 this.btnContainer.insertBefore(document.createElement("td"),fc)
29291 : this.btnContainer.appendChild(document.createElement("td")),
29292 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29295 this.syncBodyHeight();
29298 * Array of all the buttons that have been added to this dialog via addButton
29303 this.buttons.push(btn);
29308 * Sets the default button to be focused when the dialog is displayed.
29309 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29310 * @return {Roo.BasicDialog} this
29312 setDefaultButton : function(btn){
29313 this.defaultButton = btn;
29318 getHeaderFooterHeight : function(safe){
29321 height += this.header.getHeight();
29324 var fm = this.footer.getMargins();
29325 height += (this.footer.getHeight()+fm.top+fm.bottom);
29327 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29328 height += this.centerBg.getPadding("tb");
29333 syncBodyHeight : function(){
29334 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29335 var height = this.size.height - this.getHeaderFooterHeight(false);
29336 bd.setHeight(height-bd.getMargins("tb"));
29337 var hh = this.header.getHeight();
29338 var h = this.size.height-hh;
29340 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29341 bw.setHeight(h-cb.getPadding("tb"));
29342 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29343 bd.setWidth(bw.getWidth(true));
29345 this.tabs.syncHeight();
29347 this.tabs.el.repaint();
29353 * Restores the previous state of the dialog if Roo.state is configured.
29354 * @return {Roo.BasicDialog} this
29356 restoreState : function(){
29357 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29358 if(box && box.width){
29359 this.xy = [box.x, box.y];
29360 this.resizeTo(box.width, box.height);
29366 beforeShow : function(){
29368 if(this.fixedcenter){
29369 this.xy = this.el.getCenterXY(true);
29372 Roo.get(document.body).addClass("x-body-masked");
29373 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29376 this.constrainXY();
29380 animShow : function(){
29381 var b = Roo.get(this.animateTarget).getBox();
29382 this.proxy.setSize(b.width, b.height);
29383 this.proxy.setLocation(b.x, b.y);
29385 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29386 true, .35, this.showEl.createDelegate(this));
29390 * Shows the dialog.
29391 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29392 * @return {Roo.BasicDialog} this
29394 show : function(animateTarget){
29395 if (this.fireEvent("beforeshow", this) === false){
29398 if(this.syncHeightBeforeShow){
29399 this.syncBodyHeight();
29400 }else if(this.firstShow){
29401 this.firstShow = false;
29402 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29404 this.animateTarget = animateTarget || this.animateTarget;
29405 if(!this.el.isVisible()){
29407 if(this.animateTarget && Roo.get(this.animateTarget)){
29417 showEl : function(){
29419 this.el.setXY(this.xy);
29421 this.adjustAssets(true);
29424 // IE peekaboo bug - fix found by Dave Fenwick
29428 this.fireEvent("show", this);
29432 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29433 * dialog itself will receive focus.
29435 focus : function(){
29436 if(this.defaultButton){
29437 this.defaultButton.focus();
29439 this.focusEl.focus();
29444 constrainXY : function(){
29445 if(this.constraintoviewport !== false){
29446 if(!this.viewSize){
29447 if(this.container){
29448 var s = this.container.getSize();
29449 this.viewSize = [s.width, s.height];
29451 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29454 var s = Roo.get(this.container||document).getScroll();
29456 var x = this.xy[0], y = this.xy[1];
29457 var w = this.size.width, h = this.size.height;
29458 var vw = this.viewSize[0], vh = this.viewSize[1];
29459 // only move it if it needs it
29461 // first validate right/bottom
29462 if(x + w > vw+s.left){
29466 if(y + h > vh+s.top){
29470 // then make sure top/left isn't negative
29482 if(this.isVisible()){
29483 this.el.setLocation(x, y);
29484 this.adjustAssets();
29491 onDrag : function(){
29492 if(!this.proxyDrag){
29493 this.xy = this.el.getXY();
29494 this.adjustAssets();
29499 adjustAssets : function(doShow){
29500 var x = this.xy[0], y = this.xy[1];
29501 var w = this.size.width, h = this.size.height;
29502 if(doShow === true){
29504 this.shadow.show(this.el);
29510 if(this.shadow && this.shadow.isVisible()){
29511 this.shadow.show(this.el);
29513 if(this.shim && this.shim.isVisible()){
29514 this.shim.setBounds(x, y, w, h);
29519 adjustViewport : function(w, h){
29521 w = Roo.lib.Dom.getViewWidth();
29522 h = Roo.lib.Dom.getViewHeight();
29525 this.viewSize = [w, h];
29526 if(this.modal && this.mask.isVisible()){
29527 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29528 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29530 if(this.isVisible()){
29531 this.constrainXY();
29536 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29537 * shadow, proxy, mask, etc.) Also removes all event listeners.
29538 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29540 destroy : function(removeEl){
29541 if(this.isVisible()){
29542 this.animateTarget = null;
29545 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29547 this.tabs.destroy(removeEl);
29560 for(var i = 0, len = this.buttons.length; i < len; i++){
29561 this.buttons[i].destroy();
29564 this.el.removeAllListeners();
29565 if(removeEl === true){
29566 this.el.update("");
29569 Roo.DialogManager.unregister(this);
29573 startMove : function(){
29574 if(this.proxyDrag){
29577 if(this.constraintoviewport !== false){
29578 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29583 endMove : function(){
29584 if(!this.proxyDrag){
29585 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29587 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29590 this.refreshSize();
29591 this.adjustAssets();
29593 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29597 * Brings this dialog to the front of any other visible dialogs
29598 * @return {Roo.BasicDialog} this
29600 toFront : function(){
29601 Roo.DialogManager.bringToFront(this);
29606 * Sends this dialog to the back (under) of any other visible dialogs
29607 * @return {Roo.BasicDialog} this
29609 toBack : function(){
29610 Roo.DialogManager.sendToBack(this);
29615 * Centers this dialog in the viewport
29616 * @return {Roo.BasicDialog} this
29618 center : function(){
29619 var xy = this.el.getCenterXY(true);
29620 this.moveTo(xy[0], xy[1]);
29625 * Moves the dialog's top-left corner to the specified point
29626 * @param {Number} x
29627 * @param {Number} y
29628 * @return {Roo.BasicDialog} this
29630 moveTo : function(x, y){
29632 if(this.isVisible()){
29633 this.el.setXY(this.xy);
29634 this.adjustAssets();
29640 * Aligns the dialog to the specified element
29641 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29642 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29643 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29644 * @return {Roo.BasicDialog} this
29646 alignTo : function(element, position, offsets){
29647 this.xy = this.el.getAlignToXY(element, position, offsets);
29648 if(this.isVisible()){
29649 this.el.setXY(this.xy);
29650 this.adjustAssets();
29656 * Anchors an element to another element and realigns it when the window is resized.
29657 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29658 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29659 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29660 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29661 * is a number, it is used as the buffer delay (defaults to 50ms).
29662 * @return {Roo.BasicDialog} this
29664 anchorTo : function(el, alignment, offsets, monitorScroll){
29665 var action = function(){
29666 this.alignTo(el, alignment, offsets);
29668 Roo.EventManager.onWindowResize(action, this);
29669 var tm = typeof monitorScroll;
29670 if(tm != 'undefined'){
29671 Roo.EventManager.on(window, 'scroll', action, this,
29672 {buffer: tm == 'number' ? monitorScroll : 50});
29679 * Returns true if the dialog is visible
29680 * @return {Boolean}
29682 isVisible : function(){
29683 return this.el.isVisible();
29687 animHide : function(callback){
29688 var b = Roo.get(this.animateTarget).getBox();
29690 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29692 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29693 this.hideEl.createDelegate(this, [callback]));
29697 * Hides the dialog.
29698 * @param {Function} callback (optional) Function to call when the dialog is hidden
29699 * @return {Roo.BasicDialog} this
29701 hide : function(callback){
29702 if (this.fireEvent("beforehide", this) === false){
29706 this.shadow.hide();
29711 // sometimes animateTarget seems to get set.. causing problems...
29712 // this just double checks..
29713 if(this.animateTarget && Roo.get(this.animateTarget)) {
29714 this.animHide(callback);
29717 this.hideEl(callback);
29723 hideEl : function(callback){
29727 Roo.get(document.body).removeClass("x-body-masked");
29729 this.fireEvent("hide", this);
29730 if(typeof callback == "function"){
29736 hideAction : function(){
29737 this.setLeft("-10000px");
29738 this.setTop("-10000px");
29739 this.setStyle("visibility", "hidden");
29743 refreshSize : function(){
29744 this.size = this.el.getSize();
29745 this.xy = this.el.getXY();
29746 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29750 // z-index is managed by the DialogManager and may be overwritten at any time
29751 setZIndex : function(index){
29753 this.mask.setStyle("z-index", index);
29756 this.shim.setStyle("z-index", ++index);
29759 this.shadow.setZIndex(++index);
29761 this.el.setStyle("z-index", ++index);
29763 this.proxy.setStyle("z-index", ++index);
29766 this.resizer.proxy.setStyle("z-index", ++index);
29769 this.lastZIndex = index;
29773 * Returns the element for this dialog
29774 * @return {Roo.Element} The underlying dialog Element
29776 getEl : function(){
29782 * @class Roo.DialogManager
29783 * Provides global access to BasicDialogs that have been created and
29784 * support for z-indexing (layering) multiple open dialogs.
29786 Roo.DialogManager = function(){
29788 var accessList = [];
29792 var sortDialogs = function(d1, d2){
29793 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29797 var orderDialogs = function(){
29798 accessList.sort(sortDialogs);
29799 var seed = Roo.DialogManager.zseed;
29800 for(var i = 0, len = accessList.length; i < len; i++){
29801 var dlg = accessList[i];
29803 dlg.setZIndex(seed + (i*10));
29810 * The starting z-index for BasicDialogs (defaults to 9000)
29811 * @type Number The z-index value
29816 register : function(dlg){
29817 list[dlg.id] = dlg;
29818 accessList.push(dlg);
29822 unregister : function(dlg){
29823 delete list[dlg.id];
29826 if(!accessList.indexOf){
29827 for( i = 0, len = accessList.length; i < len; i++){
29828 if(accessList[i] == dlg){
29829 accessList.splice(i, 1);
29834 i = accessList.indexOf(dlg);
29836 accessList.splice(i, 1);
29842 * Gets a registered dialog by id
29843 * @param {String/Object} id The id of the dialog or a dialog
29844 * @return {Roo.BasicDialog} this
29846 get : function(id){
29847 return typeof id == "object" ? id : list[id];
29851 * Brings the specified dialog to the front
29852 * @param {String/Object} dlg The id of the dialog or a dialog
29853 * @return {Roo.BasicDialog} this
29855 bringToFront : function(dlg){
29856 dlg = this.get(dlg);
29859 dlg._lastAccess = new Date().getTime();
29866 * Sends the specified dialog to the back
29867 * @param {String/Object} dlg The id of the dialog or a dialog
29868 * @return {Roo.BasicDialog} this
29870 sendToBack : function(dlg){
29871 dlg = this.get(dlg);
29872 dlg._lastAccess = -(new Date().getTime());
29878 * Hides all dialogs
29880 hideAll : function(){
29881 for(var id in list){
29882 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29891 * @class Roo.LayoutDialog
29892 * @extends Roo.BasicDialog
29893 * Dialog which provides adjustments for working with a layout in a Dialog.
29894 * Add your necessary layout config options to the dialog's config.<br>
29895 * Example usage (including a nested layout):
29898 dialog = new Roo.LayoutDialog("download-dlg", {
29907 // layout config merges with the dialog config
29909 tabPosition: "top",
29910 alwaysShowTabs: true
29913 dialog.addKeyListener(27, dialog.hide, dialog);
29914 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29915 dialog.addButton("Build It!", this.getDownload, this);
29917 // we can even add nested layouts
29918 var innerLayout = new Roo.BorderLayout("dl-inner", {
29928 innerLayout.beginUpdate();
29929 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29930 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29931 innerLayout.endUpdate(true);
29933 var layout = dialog.getLayout();
29934 layout.beginUpdate();
29935 layout.add("center", new Roo.ContentPanel("standard-panel",
29936 {title: "Download the Source", fitToFrame:true}));
29937 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29938 {title: "Build your own roo.js"}));
29939 layout.getRegion("center").showPanel(sp);
29940 layout.endUpdate();
29944 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29945 * @param {Object} config configuration options
29947 Roo.LayoutDialog = function(el, cfg){
29950 if (typeof(cfg) == 'undefined') {
29951 config = Roo.apply({}, el);
29952 // not sure why we use documentElement here.. - it should always be body.
29953 // IE7 borks horribly if we use documentElement.
29954 // webkit also does not like documentElement - it creates a body element...
29955 el = Roo.get( document.body || document.documentElement ).createChild();
29956 //config.autoCreate = true;
29960 config.autoTabs = false;
29961 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29962 this.body.setStyle({overflow:"hidden", position:"relative"});
29963 this.layout = new Roo.BorderLayout(this.body.dom, config);
29964 this.layout.monitorWindowResize = false;
29965 this.el.addClass("x-dlg-auto-layout");
29966 // fix case when center region overwrites center function
29967 this.center = Roo.BasicDialog.prototype.center;
29968 this.on("show", this.layout.layout, this.layout, true);
29969 if (config.items) {
29970 var xitems = config.items;
29971 delete config.items;
29972 Roo.each(xitems, this.addxtype, this);
29977 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29979 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29982 endUpdate : function(){
29983 this.layout.endUpdate();
29987 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29990 beginUpdate : function(){
29991 this.layout.beginUpdate();
29995 * Get the BorderLayout for this dialog
29996 * @return {Roo.BorderLayout}
29998 getLayout : function(){
29999 return this.layout;
30002 showEl : function(){
30003 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30005 this.layout.layout();
30010 // Use the syncHeightBeforeShow config option to control this automatically
30011 syncBodyHeight : function(){
30012 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30013 if(this.layout){this.layout.layout();}
30017 * Add an xtype element (actually adds to the layout.)
30018 * @return {Object} xdata xtype object data.
30021 addxtype : function(c) {
30022 return this.layout.addxtype(c);
30026 * Ext JS Library 1.1.1
30027 * Copyright(c) 2006-2007, Ext JS, LLC.
30029 * Originally Released Under LGPL - original licence link has changed is not relivant.
30032 * <script type="text/javascript">
30036 * @class Roo.MessageBox
30037 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30041 Roo.Msg.alert('Status', 'Changes saved successfully.');
30043 // Prompt for user data:
30044 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30046 // process text value...
30050 // Show a dialog using config options:
30052 title:'Save Changes?',
30053 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30054 buttons: Roo.Msg.YESNOCANCEL,
30061 Roo.MessageBox = function(){
30062 var dlg, opt, mask, waitTimer;
30063 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30064 var buttons, activeTextEl, bwidth;
30067 var handleButton = function(button){
30069 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30073 var handleHide = function(){
30074 if(opt && opt.cls){
30075 dlg.el.removeClass(opt.cls);
30078 Roo.TaskMgr.stop(waitTimer);
30084 var updateButtons = function(b){
30087 buttons["ok"].hide();
30088 buttons["cancel"].hide();
30089 buttons["yes"].hide();
30090 buttons["no"].hide();
30091 dlg.footer.dom.style.display = 'none';
30094 dlg.footer.dom.style.display = '';
30095 for(var k in buttons){
30096 if(typeof buttons[k] != "function"){
30099 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30100 width += buttons[k].el.getWidth()+15;
30110 var handleEsc = function(d, k, e){
30111 if(opt && opt.closable !== false){
30121 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30122 * @return {Roo.BasicDialog} The BasicDialog element
30124 getDialog : function(){
30126 dlg = new Roo.BasicDialog("x-msg-box", {
30131 constraintoviewport:false,
30133 collapsible : false,
30136 width:400, height:100,
30137 buttonAlign:"center",
30138 closeClick : function(){
30139 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30140 handleButton("no");
30142 handleButton("cancel");
30146 dlg.on("hide", handleHide);
30148 dlg.addKeyListener(27, handleEsc);
30150 var bt = this.buttonText;
30151 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30152 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30153 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30154 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30155 bodyEl = dlg.body.createChild({
30157 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>'
30159 msgEl = bodyEl.dom.firstChild;
30160 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30161 textboxEl.enableDisplayMode();
30162 textboxEl.addKeyListener([10,13], function(){
30163 if(dlg.isVisible() && opt && opt.buttons){
30164 if(opt.buttons.ok){
30165 handleButton("ok");
30166 }else if(opt.buttons.yes){
30167 handleButton("yes");
30171 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30172 textareaEl.enableDisplayMode();
30173 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30174 progressEl.enableDisplayMode();
30175 var pf = progressEl.dom.firstChild;
30177 pp = Roo.get(pf.firstChild);
30178 pp.setHeight(pf.offsetHeight);
30186 * Updates the message box body text
30187 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30188 * the XHTML-compliant non-breaking space character '&#160;')
30189 * @return {Roo.MessageBox} This message box
30191 updateText : function(text){
30192 if(!dlg.isVisible() && !opt.width){
30193 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30195 msgEl.innerHTML = text || ' ';
30197 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30198 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30200 Math.min(opt.width || cw , this.maxWidth),
30201 Math.max(opt.minWidth || this.minWidth, bwidth)
30204 activeTextEl.setWidth(w);
30206 if(dlg.isVisible()){
30207 dlg.fixedcenter = false;
30209 // to big, make it scroll. = But as usual stupid IE does not support
30212 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30213 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30214 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30216 bodyEl.dom.style.height = '';
30217 bodyEl.dom.style.overflowY = '';
30220 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30222 bodyEl.dom.style.overflowX = '';
30225 dlg.setContentSize(w, bodyEl.getHeight());
30226 if(dlg.isVisible()){
30227 dlg.fixedcenter = true;
30233 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30234 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30235 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30236 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30237 * @return {Roo.MessageBox} This message box
30239 updateProgress : function(value, text){
30241 this.updateText(text);
30243 if (pp) { // weird bug on my firefox - for some reason this is not defined
30244 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30250 * Returns true if the message box is currently displayed
30251 * @return {Boolean} True if the message box is visible, else false
30253 isVisible : function(){
30254 return dlg && dlg.isVisible();
30258 * Hides the message box if it is displayed
30261 if(this.isVisible()){
30267 * Displays a new message box, or reinitializes an existing message box, based on the config options
30268 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30269 * The following config object properties are supported:
30271 Property Type Description
30272 ---------- --------------- ------------------------------------------------------------------------------------
30273 animEl String/Element An id or Element from which the message box should animate as it opens and
30274 closes (defaults to undefined)
30275 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30276 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30277 closable Boolean False to hide the top-right close button (defaults to true). Note that
30278 progress and wait dialogs will ignore this property and always hide the
30279 close button as they can only be closed programmatically.
30280 cls String A custom CSS class to apply to the message box element
30281 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30282 displayed (defaults to 75)
30283 fn Function A callback function to execute after closing the dialog. The arguments to the
30284 function will be btn (the name of the button that was clicked, if applicable,
30285 e.g. "ok"), and text (the value of the active text field, if applicable).
30286 Progress and wait dialogs will ignore this option since they do not respond to
30287 user actions and can only be closed programmatically, so any required function
30288 should be called by the same code after it closes the dialog.
30289 icon String A CSS class that provides a background image to be used as an icon for
30290 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30291 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30292 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30293 modal Boolean False to allow user interaction with the page while the message box is
30294 displayed (defaults to true)
30295 msg String A string that will replace the existing message box body text (defaults
30296 to the XHTML-compliant non-breaking space character ' ')
30297 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30298 progress Boolean True to display a progress bar (defaults to false)
30299 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30300 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30301 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30302 title String The title text
30303 value String The string value to set into the active textbox element if displayed
30304 wait Boolean True to display a progress bar (defaults to false)
30305 width Number The width of the dialog in pixels
30312 msg: 'Please enter your address:',
30314 buttons: Roo.MessageBox.OKCANCEL,
30317 animEl: 'addAddressBtn'
30320 * @param {Object} config Configuration options
30321 * @return {Roo.MessageBox} This message box
30323 show : function(options)
30326 // this causes nightmares if you show one dialog after another
30327 // especially on callbacks..
30329 if(this.isVisible()){
30332 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30333 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30334 Roo.log("New Dialog Message:" + options.msg )
30335 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30336 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30339 var d = this.getDialog();
30341 d.setTitle(opt.title || " ");
30342 d.close.setDisplayed(opt.closable !== false);
30343 activeTextEl = textboxEl;
30344 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30349 textareaEl.setHeight(typeof opt.multiline == "number" ?
30350 opt.multiline : this.defaultTextHeight);
30351 activeTextEl = textareaEl;
30360 progressEl.setDisplayed(opt.progress === true);
30361 this.updateProgress(0);
30362 activeTextEl.dom.value = opt.value || "";
30364 dlg.setDefaultButton(activeTextEl);
30366 var bs = opt.buttons;
30369 db = buttons["ok"];
30370 }else if(bs && bs.yes){
30371 db = buttons["yes"];
30373 dlg.setDefaultButton(db);
30375 bwidth = updateButtons(opt.buttons);
30376 this.updateText(opt.msg);
30378 d.el.addClass(opt.cls);
30380 d.proxyDrag = opt.proxyDrag === true;
30381 d.modal = opt.modal !== false;
30382 d.mask = opt.modal !== false ? mask : false;
30383 if(!d.isVisible()){
30384 // force it to the end of the z-index stack so it gets a cursor in FF
30385 document.body.appendChild(dlg.el.dom);
30386 d.animateTarget = null;
30387 d.show(options.animEl);
30393 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30394 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30395 * and closing the message box when the process is complete.
30396 * @param {String} title The title bar text
30397 * @param {String} msg The message box body text
30398 * @return {Roo.MessageBox} This message box
30400 progress : function(title, msg){
30407 minWidth: this.minProgressWidth,
30414 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30415 * If a callback function is passed it will be called after the user clicks the button, and the
30416 * id of the button that was clicked will be passed as the only parameter to the callback
30417 * (could also be the top-right close button).
30418 * @param {String} title The title bar text
30419 * @param {String} msg The message box body text
30420 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30421 * @param {Object} scope (optional) The scope of the callback function
30422 * @return {Roo.MessageBox} This message box
30424 alert : function(title, msg, fn, scope){
30437 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30438 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30439 * You are responsible for closing the message box when the process is complete.
30440 * @param {String} msg The message box body text
30441 * @param {String} title (optional) The title bar text
30442 * @return {Roo.MessageBox} This message box
30444 wait : function(msg, title){
30455 waitTimer = Roo.TaskMgr.start({
30457 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30465 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30466 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30467 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30468 * @param {String} title The title bar text
30469 * @param {String} msg The message box body text
30470 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30471 * @param {Object} scope (optional) The scope of the callback function
30472 * @return {Roo.MessageBox} This message box
30474 confirm : function(title, msg, fn, scope){
30478 buttons: this.YESNO,
30487 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30488 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30489 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30490 * (could also be the top-right close button) and the text that was entered will be passed as the two
30491 * parameters to the callback.
30492 * @param {String} title The title bar text
30493 * @param {String} msg The message box body text
30494 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30495 * @param {Object} scope (optional) The scope of the callback function
30496 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30497 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30498 * @return {Roo.MessageBox} This message box
30500 prompt : function(title, msg, fn, scope, multiline){
30504 buttons: this.OKCANCEL,
30509 multiline: multiline,
30516 * Button config that displays a single OK button
30521 * Button config that displays Yes and No buttons
30524 YESNO : {yes:true, no:true},
30526 * Button config that displays OK and Cancel buttons
30529 OKCANCEL : {ok:true, cancel:true},
30531 * Button config that displays Yes, No and Cancel buttons
30534 YESNOCANCEL : {yes:true, no:true, cancel:true},
30537 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30540 defaultTextHeight : 75,
30542 * The maximum width in pixels of the message box (defaults to 600)
30547 * The minimum width in pixels of the message box (defaults to 100)
30552 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30553 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30556 minProgressWidth : 250,
30558 * An object containing the default button text strings that can be overriden for localized language support.
30559 * Supported properties are: ok, cancel, yes and no.
30560 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30573 * Shorthand for {@link Roo.MessageBox}
30575 Roo.Msg = Roo.MessageBox;/*
30577 * Ext JS Library 1.1.1
30578 * Copyright(c) 2006-2007, Ext JS, LLC.
30580 * Originally Released Under LGPL - original licence link has changed is not relivant.
30583 * <script type="text/javascript">
30586 * @class Roo.QuickTips
30587 * Provides attractive and customizable tooltips for any element.
30590 Roo.QuickTips = function(){
30591 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30592 var ce, bd, xy, dd;
30593 var visible = false, disabled = true, inited = false;
30594 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30596 var onOver = function(e){
30600 var t = e.getTarget();
30601 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30604 if(ce && t == ce.el){
30605 clearTimeout(hideProc);
30608 if(t && tagEls[t.id]){
30609 tagEls[t.id].el = t;
30610 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30613 var ttp, et = Roo.fly(t);
30614 var ns = cfg.namespace;
30615 if(tm.interceptTitles && t.title){
30618 t.removeAttribute("title");
30619 e.preventDefault();
30621 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30624 showProc = show.defer(tm.showDelay, tm, [{
30627 width: et.getAttributeNS(ns, cfg.width),
30628 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30629 title: et.getAttributeNS(ns, cfg.title),
30630 cls: et.getAttributeNS(ns, cfg.cls)
30635 var onOut = function(e){
30636 clearTimeout(showProc);
30637 var t = e.getTarget();
30638 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30639 hideProc = setTimeout(hide, tm.hideDelay);
30643 var onMove = function(e){
30649 if(tm.trackMouse && ce){
30654 var onDown = function(e){
30655 clearTimeout(showProc);
30656 clearTimeout(hideProc);
30658 if(tm.hideOnClick){
30661 tm.enable.defer(100, tm);
30666 var getPad = function(){
30667 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30670 var show = function(o){
30674 clearTimeout(dismissProc);
30676 if(removeCls){ // in case manually hidden
30677 el.removeClass(removeCls);
30681 el.addClass(ce.cls);
30682 removeCls = ce.cls;
30685 tipTitle.update(ce.title);
30688 tipTitle.update('');
30691 el.dom.style.width = tm.maxWidth+'px';
30692 //tipBody.dom.style.width = '';
30693 tipBodyText.update(o.text);
30694 var p = getPad(), w = ce.width;
30696 var td = tipBodyText.dom;
30697 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30698 if(aw > tm.maxWidth){
30700 }else if(aw < tm.minWidth){
30706 //tipBody.setWidth(w);
30707 el.setWidth(parseInt(w, 10) + p);
30708 if(ce.autoHide === false){
30709 close.setDisplayed(true);
30714 close.setDisplayed(false);
30720 el.avoidY = xy[1]-18;
30725 el.setStyle("visibility", "visible");
30726 el.fadeIn({callback: afterShow});
30732 var afterShow = function(){
30736 if(tm.autoDismiss && ce.autoHide !== false){
30737 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30742 var hide = function(noanim){
30743 clearTimeout(dismissProc);
30744 clearTimeout(hideProc);
30746 if(el.isVisible()){
30748 if(noanim !== true && tm.animate){
30749 el.fadeOut({callback: afterHide});
30756 var afterHide = function(){
30759 el.removeClass(removeCls);
30766 * @cfg {Number} minWidth
30767 * The minimum width of the quick tip (defaults to 40)
30771 * @cfg {Number} maxWidth
30772 * The maximum width of the quick tip (defaults to 300)
30776 * @cfg {Boolean} interceptTitles
30777 * True to automatically use the element's DOM title value if available (defaults to false)
30779 interceptTitles : false,
30781 * @cfg {Boolean} trackMouse
30782 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30784 trackMouse : false,
30786 * @cfg {Boolean} hideOnClick
30787 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30789 hideOnClick : true,
30791 * @cfg {Number} showDelay
30792 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30796 * @cfg {Number} hideDelay
30797 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30801 * @cfg {Boolean} autoHide
30802 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30803 * Used in conjunction with hideDelay.
30808 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30809 * (defaults to true). Used in conjunction with autoDismissDelay.
30811 autoDismiss : true,
30814 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30816 autoDismissDelay : 5000,
30818 * @cfg {Boolean} animate
30819 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30824 * @cfg {String} title
30825 * Title text to display (defaults to ''). This can be any valid HTML markup.
30829 * @cfg {String} text
30830 * Body text to display (defaults to ''). This can be any valid HTML markup.
30834 * @cfg {String} cls
30835 * A CSS class to apply to the base quick tip element (defaults to '').
30839 * @cfg {Number} width
30840 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30841 * minWidth or maxWidth.
30846 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30847 * or display QuickTips in a page.
30850 tm = Roo.QuickTips;
30851 cfg = tm.tagConfig;
30853 if(!Roo.isReady){ // allow calling of init() before onReady
30854 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30857 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30858 el.fxDefaults = {stopFx: true};
30859 // maximum custom styling
30860 //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>');
30861 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>');
30862 tipTitle = el.child('h3');
30863 tipTitle.enableDisplayMode("block");
30864 tipBody = el.child('div.x-tip-bd');
30865 tipBodyText = el.child('div.x-tip-bd-inner');
30866 //bdLeft = el.child('div.x-tip-bd-left');
30867 //bdRight = el.child('div.x-tip-bd-right');
30868 close = el.child('div.x-tip-close');
30869 close.enableDisplayMode("block");
30870 close.on("click", hide);
30871 var d = Roo.get(document);
30872 d.on("mousedown", onDown);
30873 d.on("mouseover", onOver);
30874 d.on("mouseout", onOut);
30875 d.on("mousemove", onMove);
30876 esc = d.addKeyListener(27, hide);
30879 dd = el.initDD("default", null, {
30880 onDrag : function(){
30884 dd.setHandleElId(tipTitle.id);
30893 * Configures a new quick tip instance and assigns it to a target element. The following config options
30896 Property Type Description
30897 ---------- --------------------- ------------------------------------------------------------------------
30898 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30900 * @param {Object} config The config object
30902 register : function(config){
30903 var cs = config instanceof Array ? config : arguments;
30904 for(var i = 0, len = cs.length; i < len; i++) {
30906 var target = c.target;
30908 if(target instanceof Array){
30909 for(var j = 0, jlen = target.length; j < jlen; j++){
30910 tagEls[target[j]] = c;
30913 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30920 * Removes this quick tip from its element and destroys it.
30921 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30923 unregister : function(el){
30924 delete tagEls[Roo.id(el)];
30928 * Enable this quick tip.
30930 enable : function(){
30931 if(inited && disabled){
30933 if(locks.length < 1){
30940 * Disable this quick tip.
30942 disable : function(){
30944 clearTimeout(showProc);
30945 clearTimeout(hideProc);
30946 clearTimeout(dismissProc);
30954 * Returns true if the quick tip is enabled, else false.
30956 isEnabled : function(){
30963 attribute : "qtip",
30973 // backwards compat
30974 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30976 * Ext JS Library 1.1.1
30977 * Copyright(c) 2006-2007, Ext JS, LLC.
30979 * Originally Released Under LGPL - original licence link has changed is not relivant.
30982 * <script type="text/javascript">
30987 * @class Roo.tree.TreePanel
30988 * @extends Roo.data.Tree
30990 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30991 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30992 * @cfg {Boolean} enableDD true to enable drag and drop
30993 * @cfg {Boolean} enableDrag true to enable just drag
30994 * @cfg {Boolean} enableDrop true to enable just drop
30995 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30996 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30997 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30998 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30999 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31000 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31001 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31002 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31003 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31004 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31005 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31006 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31007 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31008 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31009 * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
31010 * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
31013 * @param {String/HTMLElement/Element} el The container element
31014 * @param {Object} config
31016 Roo.tree.TreePanel = function(el, config){
31018 var loader = false;
31020 root = config.root;
31021 delete config.root;
31023 if (config.loader) {
31024 loader = config.loader;
31025 delete config.loader;
31028 Roo.apply(this, config);
31029 Roo.tree.TreePanel.superclass.constructor.call(this);
31030 this.el = Roo.get(el);
31031 this.el.addClass('x-tree');
31032 //console.log(root);
31034 this.setRootNode( Roo.factory(root, Roo.tree));
31037 this.loader = Roo.factory(loader, Roo.tree);
31040 * Read-only. The id of the container element becomes this TreePanel's id.
31042 this.id = this.el.id;
31045 * @event beforeload
31046 * Fires before a node is loaded, return false to cancel
31047 * @param {Node} node The node being loaded
31049 "beforeload" : true,
31052 * Fires when a node is loaded
31053 * @param {Node} node The node that was loaded
31057 * @event textchange
31058 * Fires when the text for a node is changed
31059 * @param {Node} node The node
31060 * @param {String} text The new text
31061 * @param {String} oldText The old text
31063 "textchange" : true,
31065 * @event beforeexpand
31066 * Fires before a node is expanded, return false to cancel.
31067 * @param {Node} node The node
31068 * @param {Boolean} deep
31069 * @param {Boolean} anim
31071 "beforeexpand" : true,
31073 * @event beforecollapse
31074 * Fires before a node is collapsed, return false to cancel.
31075 * @param {Node} node The node
31076 * @param {Boolean} deep
31077 * @param {Boolean} anim
31079 "beforecollapse" : true,
31082 * Fires when a node is expanded
31083 * @param {Node} node The node
31087 * @event disabledchange
31088 * Fires when the disabled status of a node changes
31089 * @param {Node} node The node
31090 * @param {Boolean} disabled
31092 "disabledchange" : true,
31095 * Fires when a node is collapsed
31096 * @param {Node} node The node
31100 * @event beforeclick
31101 * Fires before click processing on a node. Return false to cancel the default action.
31102 * @param {Node} node The node
31103 * @param {Roo.EventObject} e The event object
31105 "beforeclick":true,
31107 * @event checkchange
31108 * Fires when a node with a checkbox's checked property changes
31109 * @param {Node} this This node
31110 * @param {Boolean} checked
31112 "checkchange":true,
31115 * Fires when a node is clicked
31116 * @param {Node} node The node
31117 * @param {Roo.EventObject} e The event object
31122 * Fires when a node is double clicked
31123 * @param {Node} node The node
31124 * @param {Roo.EventObject} e The event object
31128 * @event contextmenu
31129 * Fires when a node is right clicked
31130 * @param {Node} node The node
31131 * @param {Roo.EventObject} e The event object
31133 "contextmenu":true,
31135 * @event beforechildrenrendered
31136 * Fires right before the child nodes for a node are rendered
31137 * @param {Node} node The node
31139 "beforechildrenrendered":true,
31142 * Fires when a node starts being dragged
31143 * @param {Roo.tree.TreePanel} this
31144 * @param {Roo.tree.TreeNode} node
31145 * @param {event} e The raw browser event
31147 "startdrag" : true,
31150 * Fires when a drag operation is complete
31151 * @param {Roo.tree.TreePanel} this
31152 * @param {Roo.tree.TreeNode} node
31153 * @param {event} e The raw browser event
31158 * Fires when a dragged node is dropped on a valid DD target
31159 * @param {Roo.tree.TreePanel} this
31160 * @param {Roo.tree.TreeNode} node
31161 * @param {DD} dd The dd it was dropped on
31162 * @param {event} e The raw browser event
31166 * @event beforenodedrop
31167 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31168 * passed to handlers has the following properties:<br />
31169 * <ul style="padding:5px;padding-left:16px;">
31170 * <li>tree - The TreePanel</li>
31171 * <li>target - The node being targeted for the drop</li>
31172 * <li>data - The drag data from the drag source</li>
31173 * <li>point - The point of the drop - append, above or below</li>
31174 * <li>source - The drag source</li>
31175 * <li>rawEvent - Raw mouse event</li>
31176 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31177 * to be inserted by setting them on this object.</li>
31178 * <li>cancel - Set this to true to cancel the drop.</li>
31180 * @param {Object} dropEvent
31182 "beforenodedrop" : true,
31185 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31186 * passed to handlers has the following properties:<br />
31187 * <ul style="padding:5px;padding-left:16px;">
31188 * <li>tree - The TreePanel</li>
31189 * <li>target - The node being targeted for the drop</li>
31190 * <li>data - The drag data from the drag source</li>
31191 * <li>point - The point of the drop - append, above or below</li>
31192 * <li>source - The drag source</li>
31193 * <li>rawEvent - Raw mouse event</li>
31194 * <li>dropNode - Dropped node(s).</li>
31196 * @param {Object} dropEvent
31200 * @event nodedragover
31201 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31202 * passed to handlers has the following properties:<br />
31203 * <ul style="padding:5px;padding-left:16px;">
31204 * <li>tree - The TreePanel</li>
31205 * <li>target - The node being targeted for the drop</li>
31206 * <li>data - The drag data from the drag source</li>
31207 * <li>point - The point of the drop - append, above or below</li>
31208 * <li>source - The drag source</li>
31209 * <li>rawEvent - Raw mouse event</li>
31210 * <li>dropNode - Drop node(s) provided by the source.</li>
31211 * <li>cancel - Set this to true to signal drop not allowed.</li>
31213 * @param {Object} dragOverEvent
31215 "nodedragover" : true
31218 if(this.singleExpand){
31219 this.on("beforeexpand", this.restrictExpand, this);
31222 this.editor.tree = this;
31223 this.editor = Roo.factory(this.editor, Roo.tree);
31226 if (this.selModel) {
31227 this.selModel = Roo.factory(this.selModel, Roo.tree);
31231 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31232 rootVisible : true,
31233 animate: Roo.enableFx,
31236 hlDrop : Roo.enableFx,
31240 rendererTip: false,
31242 restrictExpand : function(node){
31243 var p = node.parentNode;
31245 if(p.expandedChild && p.expandedChild.parentNode == p){
31246 p.expandedChild.collapse();
31248 p.expandedChild = node;
31252 // private override
31253 setRootNode : function(node){
31254 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31255 if(!this.rootVisible){
31256 node.ui = new Roo.tree.RootTreeNodeUI(node);
31262 * Returns the container element for this TreePanel
31264 getEl : function(){
31269 * Returns the default TreeLoader for this TreePanel
31271 getLoader : function(){
31272 return this.loader;
31278 expandAll : function(){
31279 this.root.expand(true);
31283 * Collapse all nodes
31285 collapseAll : function(){
31286 this.root.collapse(true);
31290 * Returns the selection model used by this TreePanel
31292 getSelectionModel : function(){
31293 if(!this.selModel){
31294 this.selModel = new Roo.tree.DefaultSelectionModel();
31296 return this.selModel;
31300 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31301 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31302 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31305 getChecked : function(a, startNode){
31306 startNode = startNode || this.root;
31308 var f = function(){
31309 if(this.attributes.checked){
31310 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31313 startNode.cascade(f);
31318 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31319 * @param {String} path
31320 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31321 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31322 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31324 expandPath : function(path, attr, callback){
31325 attr = attr || "id";
31326 var keys = path.split(this.pathSeparator);
31327 var curNode = this.root;
31328 if(curNode.attributes[attr] != keys[1]){ // invalid root
31330 callback(false, null);
31335 var f = function(){
31336 if(++index == keys.length){
31338 callback(true, curNode);
31342 var c = curNode.findChild(attr, keys[index]);
31345 callback(false, curNode);
31350 c.expand(false, false, f);
31352 curNode.expand(false, false, f);
31356 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31357 * @param {String} path
31358 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31359 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31360 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31362 selectPath : function(path, attr, callback){
31363 attr = attr || "id";
31364 var keys = path.split(this.pathSeparator);
31365 var v = keys.pop();
31366 if(keys.length > 0){
31367 var f = function(success, node){
31368 if(success && node){
31369 var n = node.findChild(attr, v);
31375 }else if(callback){
31376 callback(false, n);
31380 callback(false, n);
31384 this.expandPath(keys.join(this.pathSeparator), attr, f);
31386 this.root.select();
31388 callback(true, this.root);
31393 getTreeEl : function(){
31398 * Trigger rendering of this TreePanel
31400 render : function(){
31401 if (this.innerCt) {
31402 return this; // stop it rendering more than once!!
31405 this.innerCt = this.el.createChild({tag:"ul",
31406 cls:"x-tree-root-ct " +
31407 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31409 if(this.containerScroll){
31410 Roo.dd.ScrollManager.register(this.el);
31412 if((this.enableDD || this.enableDrop) && !this.dropZone){
31414 * The dropZone used by this tree if drop is enabled
31415 * @type Roo.tree.TreeDropZone
31417 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31418 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31421 if((this.enableDD || this.enableDrag) && !this.dragZone){
31423 * The dragZone used by this tree if drag is enabled
31424 * @type Roo.tree.TreeDragZone
31426 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31427 ddGroup: this.ddGroup || "TreeDD",
31428 scroll: this.ddScroll
31431 this.getSelectionModel().init(this);
31433 console.log("ROOT not set in tree");
31436 this.root.render();
31437 if(!this.rootVisible){
31438 this.root.renderChildren();
31444 * Ext JS Library 1.1.1
31445 * Copyright(c) 2006-2007, Ext JS, LLC.
31447 * Originally Released Under LGPL - original licence link has changed is not relivant.
31450 * <script type="text/javascript">
31455 * @class Roo.tree.DefaultSelectionModel
31456 * @extends Roo.util.Observable
31457 * The default single selection for a TreePanel.
31458 * @param {Object} cfg Configuration
31460 Roo.tree.DefaultSelectionModel = function(cfg){
31461 this.selNode = null;
31467 * @event selectionchange
31468 * Fires when the selected node changes
31469 * @param {DefaultSelectionModel} this
31470 * @param {TreeNode} node the new selection
31472 "selectionchange" : true,
31475 * @event beforeselect
31476 * Fires before the selected node changes, return false to cancel the change
31477 * @param {DefaultSelectionModel} this
31478 * @param {TreeNode} node the new selection
31479 * @param {TreeNode} node the old selection
31481 "beforeselect" : true
31484 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31487 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31488 init : function(tree){
31490 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31491 tree.on("click", this.onNodeClick, this);
31494 onNodeClick : function(node, e){
31495 if (e.ctrlKey && this.selNode == node) {
31496 this.unselect(node);
31504 * @param {TreeNode} node The node to select
31505 * @return {TreeNode} The selected node
31507 select : function(node){
31508 var last = this.selNode;
31509 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31511 last.ui.onSelectedChange(false);
31513 this.selNode = node;
31514 node.ui.onSelectedChange(true);
31515 this.fireEvent("selectionchange", this, node, last);
31522 * @param {TreeNode} node The node to unselect
31524 unselect : function(node){
31525 if(this.selNode == node){
31526 this.clearSelections();
31531 * Clear all selections
31533 clearSelections : function(){
31534 var n = this.selNode;
31536 n.ui.onSelectedChange(false);
31537 this.selNode = null;
31538 this.fireEvent("selectionchange", this, null);
31544 * Get the selected node
31545 * @return {TreeNode} The selected node
31547 getSelectedNode : function(){
31548 return this.selNode;
31552 * Returns true if the node is selected
31553 * @param {TreeNode} node The node to check
31554 * @return {Boolean}
31556 isSelected : function(node){
31557 return this.selNode == node;
31561 * Selects the node above the selected node in the tree, intelligently walking the nodes
31562 * @return TreeNode The new selection
31564 selectPrevious : function(){
31565 var s = this.selNode || this.lastSelNode;
31569 var ps = s.previousSibling;
31571 if(!ps.isExpanded() || ps.childNodes.length < 1){
31572 return this.select(ps);
31574 var lc = ps.lastChild;
31575 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31578 return this.select(lc);
31580 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31581 return this.select(s.parentNode);
31587 * Selects the node above the selected node in the tree, intelligently walking the nodes
31588 * @return TreeNode The new selection
31590 selectNext : function(){
31591 var s = this.selNode || this.lastSelNode;
31595 if(s.firstChild && s.isExpanded()){
31596 return this.select(s.firstChild);
31597 }else if(s.nextSibling){
31598 return this.select(s.nextSibling);
31599 }else if(s.parentNode){
31601 s.parentNode.bubble(function(){
31602 if(this.nextSibling){
31603 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31612 onKeyDown : function(e){
31613 var s = this.selNode || this.lastSelNode;
31614 // undesirable, but required
31619 var k = e.getKey();
31627 this.selectPrevious();
31630 e.preventDefault();
31631 if(s.hasChildNodes()){
31632 if(!s.isExpanded()){
31634 }else if(s.firstChild){
31635 this.select(s.firstChild, e);
31640 e.preventDefault();
31641 if(s.hasChildNodes() && s.isExpanded()){
31643 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31644 this.select(s.parentNode, e);
31652 * @class Roo.tree.MultiSelectionModel
31653 * @extends Roo.util.Observable
31654 * Multi selection for a TreePanel.
31655 * @param {Object} cfg Configuration
31657 Roo.tree.MultiSelectionModel = function(){
31658 this.selNodes = [];
31662 * @event selectionchange
31663 * Fires when the selected nodes change
31664 * @param {MultiSelectionModel} this
31665 * @param {Array} nodes Array of the selected nodes
31667 "selectionchange" : true
31669 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
31673 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31674 init : function(tree){
31676 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31677 tree.on("click", this.onNodeClick, this);
31680 onNodeClick : function(node, e){
31681 this.select(node, e, e.ctrlKey);
31686 * @param {TreeNode} node The node to select
31687 * @param {EventObject} e (optional) An event associated with the selection
31688 * @param {Boolean} keepExisting True to retain existing selections
31689 * @return {TreeNode} The selected node
31691 select : function(node, e, keepExisting){
31692 if(keepExisting !== true){
31693 this.clearSelections(true);
31695 if(this.isSelected(node)){
31696 this.lastSelNode = node;
31699 this.selNodes.push(node);
31700 this.selMap[node.id] = node;
31701 this.lastSelNode = node;
31702 node.ui.onSelectedChange(true);
31703 this.fireEvent("selectionchange", this, this.selNodes);
31709 * @param {TreeNode} node The node to unselect
31711 unselect : function(node){
31712 if(this.selMap[node.id]){
31713 node.ui.onSelectedChange(false);
31714 var sn = this.selNodes;
31717 index = sn.indexOf(node);
31719 for(var i = 0, len = sn.length; i < len; i++){
31727 this.selNodes.splice(index, 1);
31729 delete this.selMap[node.id];
31730 this.fireEvent("selectionchange", this, this.selNodes);
31735 * Clear all selections
31737 clearSelections : function(suppressEvent){
31738 var sn = this.selNodes;
31740 for(var i = 0, len = sn.length; i < len; i++){
31741 sn[i].ui.onSelectedChange(false);
31743 this.selNodes = [];
31745 if(suppressEvent !== true){
31746 this.fireEvent("selectionchange", this, this.selNodes);
31752 * Returns true if the node is selected
31753 * @param {TreeNode} node The node to check
31754 * @return {Boolean}
31756 isSelected : function(node){
31757 return this.selMap[node.id] ? true : false;
31761 * Returns an array of the selected nodes
31764 getSelectedNodes : function(){
31765 return this.selNodes;
31768 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31770 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31772 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31775 * Ext JS Library 1.1.1
31776 * Copyright(c) 2006-2007, Ext JS, LLC.
31778 * Originally Released Under LGPL - original licence link has changed is not relivant.
31781 * <script type="text/javascript">
31785 * @class Roo.tree.TreeNode
31786 * @extends Roo.data.Node
31787 * @cfg {String} text The text for this node
31788 * @cfg {Boolean} expanded true to start the node expanded
31789 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31790 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31791 * @cfg {Boolean} disabled true to start the node disabled
31792 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31793 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31794 * @cfg {String} cls A css class to be added to the node
31795 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31796 * @cfg {String} href URL of the link used for the node (defaults to #)
31797 * @cfg {String} hrefTarget target frame for the link
31798 * @cfg {String} qtip An Ext QuickTip for the node
31799 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31800 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31801 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31802 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31803 * (defaults to undefined with no checkbox rendered)
31805 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31807 Roo.tree.TreeNode = function(attributes){
31808 attributes = attributes || {};
31809 if(typeof attributes == "string"){
31810 attributes = {text: attributes};
31812 this.childrenRendered = false;
31813 this.rendered = false;
31814 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31815 this.expanded = attributes.expanded === true;
31816 this.isTarget = attributes.isTarget !== false;
31817 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31818 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31821 * Read-only. The text for this node. To change it use setText().
31824 this.text = attributes.text;
31826 * True if this node is disabled.
31829 this.disabled = attributes.disabled === true;
31833 * @event textchange
31834 * Fires when the text for this node is changed
31835 * @param {Node} this This node
31836 * @param {String} text The new text
31837 * @param {String} oldText The old text
31839 "textchange" : true,
31841 * @event beforeexpand
31842 * Fires before this node is expanded, return false to cancel.
31843 * @param {Node} this This node
31844 * @param {Boolean} deep
31845 * @param {Boolean} anim
31847 "beforeexpand" : true,
31849 * @event beforecollapse
31850 * Fires before this node is collapsed, return false to cancel.
31851 * @param {Node} this This node
31852 * @param {Boolean} deep
31853 * @param {Boolean} anim
31855 "beforecollapse" : true,
31858 * Fires when this node is expanded
31859 * @param {Node} this This node
31863 * @event disabledchange
31864 * Fires when the disabled status of this node changes
31865 * @param {Node} this This node
31866 * @param {Boolean} disabled
31868 "disabledchange" : true,
31871 * Fires when this node is collapsed
31872 * @param {Node} this This node
31876 * @event beforeclick
31877 * Fires before click processing. Return false to cancel the default action.
31878 * @param {Node} this This node
31879 * @param {Roo.EventObject} e The event object
31881 "beforeclick":true,
31883 * @event checkchange
31884 * Fires when a node with a checkbox's checked property changes
31885 * @param {Node} this This node
31886 * @param {Boolean} checked
31888 "checkchange":true,
31891 * Fires when this node is clicked
31892 * @param {Node} this This node
31893 * @param {Roo.EventObject} e The event object
31898 * Fires when this node is double clicked
31899 * @param {Node} this This node
31900 * @param {Roo.EventObject} e The event object
31904 * @event contextmenu
31905 * Fires when this node is right clicked
31906 * @param {Node} this This node
31907 * @param {Roo.EventObject} e The event object
31909 "contextmenu":true,
31911 * @event beforechildrenrendered
31912 * Fires right before the child nodes for this node are rendered
31913 * @param {Node} this This node
31915 "beforechildrenrendered":true
31918 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31921 * Read-only. The UI for this node
31924 this.ui = new uiClass(this);
31926 // finally support items[]
31927 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
31932 Roo.each(this.attributes.items, function(c) {
31933 this.appendChild(Roo.factory(c,Roo.Tree));
31935 delete this.attributes.items;
31940 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31941 preventHScroll: true,
31943 * Returns true if this node is expanded
31944 * @return {Boolean}
31946 isExpanded : function(){
31947 return this.expanded;
31951 * Returns the UI object for this node
31952 * @return {TreeNodeUI}
31954 getUI : function(){
31958 // private override
31959 setFirstChild : function(node){
31960 var of = this.firstChild;
31961 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31962 if(this.childrenRendered && of && node != of){
31963 of.renderIndent(true, true);
31966 this.renderIndent(true, true);
31970 // private override
31971 setLastChild : function(node){
31972 var ol = this.lastChild;
31973 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31974 if(this.childrenRendered && ol && node != ol){
31975 ol.renderIndent(true, true);
31978 this.renderIndent(true, true);
31982 // these methods are overridden to provide lazy rendering support
31983 // private override
31984 appendChild : function()
31986 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31987 if(node && this.childrenRendered){
31990 this.ui.updateExpandIcon();
31994 // private override
31995 removeChild : function(node){
31996 this.ownerTree.getSelectionModel().unselect(node);
31997 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31998 // if it's been rendered remove dom node
31999 if(this.childrenRendered){
32002 if(this.childNodes.length < 1){
32003 this.collapse(false, false);
32005 this.ui.updateExpandIcon();
32007 if(!this.firstChild) {
32008 this.childrenRendered = false;
32013 // private override
32014 insertBefore : function(node, refNode){
32015 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32016 if(newNode && refNode && this.childrenRendered){
32019 this.ui.updateExpandIcon();
32024 * Sets the text for this node
32025 * @param {String} text
32027 setText : function(text){
32028 var oldText = this.text;
32030 this.attributes.text = text;
32031 if(this.rendered){ // event without subscribing
32032 this.ui.onTextChange(this, text, oldText);
32034 this.fireEvent("textchange", this, text, oldText);
32038 * Triggers selection of this node
32040 select : function(){
32041 this.getOwnerTree().getSelectionModel().select(this);
32045 * Triggers deselection of this node
32047 unselect : function(){
32048 this.getOwnerTree().getSelectionModel().unselect(this);
32052 * Returns true if this node is selected
32053 * @return {Boolean}
32055 isSelected : function(){
32056 return this.getOwnerTree().getSelectionModel().isSelected(this);
32060 * Expand this node.
32061 * @param {Boolean} deep (optional) True to expand all children as well
32062 * @param {Boolean} anim (optional) false to cancel the default animation
32063 * @param {Function} callback (optional) A callback to be called when
32064 * expanding this node completes (does not wait for deep expand to complete).
32065 * Called with 1 parameter, this node.
32067 expand : function(deep, anim, callback){
32068 if(!this.expanded){
32069 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32072 if(!this.childrenRendered){
32073 this.renderChildren();
32075 this.expanded = true;
32076 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32077 this.ui.animExpand(function(){
32078 this.fireEvent("expand", this);
32079 if(typeof callback == "function"){
32083 this.expandChildNodes(true);
32085 }.createDelegate(this));
32089 this.fireEvent("expand", this);
32090 if(typeof callback == "function"){
32095 if(typeof callback == "function"){
32100 this.expandChildNodes(true);
32104 isHiddenRoot : function(){
32105 return this.isRoot && !this.getOwnerTree().rootVisible;
32109 * Collapse this node.
32110 * @param {Boolean} deep (optional) True to collapse all children as well
32111 * @param {Boolean} anim (optional) false to cancel the default animation
32113 collapse : function(deep, anim){
32114 if(this.expanded && !this.isHiddenRoot()){
32115 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32118 this.expanded = false;
32119 if((this.getOwnerTree().animate && anim !== false) || anim){
32120 this.ui.animCollapse(function(){
32121 this.fireEvent("collapse", this);
32123 this.collapseChildNodes(true);
32125 }.createDelegate(this));
32128 this.ui.collapse();
32129 this.fireEvent("collapse", this);
32133 var cs = this.childNodes;
32134 for(var i = 0, len = cs.length; i < len; i++) {
32135 cs[i].collapse(true, false);
32141 delayedExpand : function(delay){
32142 if(!this.expandProcId){
32143 this.expandProcId = this.expand.defer(delay, this);
32148 cancelExpand : function(){
32149 if(this.expandProcId){
32150 clearTimeout(this.expandProcId);
32152 this.expandProcId = false;
32156 * Toggles expanded/collapsed state of the node
32158 toggle : function(){
32167 * Ensures all parent nodes are expanded
32169 ensureVisible : function(callback){
32170 var tree = this.getOwnerTree();
32171 tree.expandPath(this.parentNode.getPath(), false, function(){
32172 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32173 Roo.callback(callback);
32174 }.createDelegate(this));
32178 * Expand all child nodes
32179 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32181 expandChildNodes : function(deep){
32182 var cs = this.childNodes;
32183 for(var i = 0, len = cs.length; i < len; i++) {
32184 cs[i].expand(deep);
32189 * Collapse all child nodes
32190 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32192 collapseChildNodes : function(deep){
32193 var cs = this.childNodes;
32194 for(var i = 0, len = cs.length; i < len; i++) {
32195 cs[i].collapse(deep);
32200 * Disables this node
32202 disable : function(){
32203 this.disabled = true;
32205 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32206 this.ui.onDisableChange(this, true);
32208 this.fireEvent("disabledchange", this, true);
32212 * Enables this node
32214 enable : function(){
32215 this.disabled = false;
32216 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32217 this.ui.onDisableChange(this, false);
32219 this.fireEvent("disabledchange", this, false);
32223 renderChildren : function(suppressEvent){
32224 if(suppressEvent !== false){
32225 this.fireEvent("beforechildrenrendered", this);
32227 var cs = this.childNodes;
32228 for(var i = 0, len = cs.length; i < len; i++){
32229 cs[i].render(true);
32231 this.childrenRendered = true;
32235 sort : function(fn, scope){
32236 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32237 if(this.childrenRendered){
32238 var cs = this.childNodes;
32239 for(var i = 0, len = cs.length; i < len; i++){
32240 cs[i].render(true);
32246 render : function(bulkRender){
32247 this.ui.render(bulkRender);
32248 if(!this.rendered){
32249 this.rendered = true;
32251 this.expanded = false;
32252 this.expand(false, false);
32258 renderIndent : function(deep, refresh){
32260 this.ui.childIndent = null;
32262 this.ui.renderIndent();
32263 if(deep === true && this.childrenRendered){
32264 var cs = this.childNodes;
32265 for(var i = 0, len = cs.length; i < len; i++){
32266 cs[i].renderIndent(true, refresh);
32272 * Ext JS Library 1.1.1
32273 * Copyright(c) 2006-2007, Ext JS, LLC.
32275 * Originally Released Under LGPL - original licence link has changed is not relivant.
32278 * <script type="text/javascript">
32282 * @class Roo.tree.AsyncTreeNode
32283 * @extends Roo.tree.TreeNode
32284 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32286 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32288 Roo.tree.AsyncTreeNode = function(config){
32289 this.loaded = false;
32290 this.loading = false;
32291 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32293 * @event beforeload
32294 * Fires before this node is loaded, return false to cancel
32295 * @param {Node} this This node
32297 this.addEvents({'beforeload':true, 'load': true});
32300 * Fires when this node is loaded
32301 * @param {Node} this This node
32304 * The loader used by this node (defaults to using the tree's defined loader)
32309 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32310 expand : function(deep, anim, callback){
32311 if(this.loading){ // if an async load is already running, waiting til it's done
32313 var f = function(){
32314 if(!this.loading){ // done loading
32315 clearInterval(timer);
32316 this.expand(deep, anim, callback);
32318 }.createDelegate(this);
32319 timer = setInterval(f, 200);
32323 if(this.fireEvent("beforeload", this) === false){
32326 this.loading = true;
32327 this.ui.beforeLoad(this);
32328 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32330 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32334 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32338 * Returns true if this node is currently loading
32339 * @return {Boolean}
32341 isLoading : function(){
32342 return this.loading;
32345 loadComplete : function(deep, anim, callback){
32346 this.loading = false;
32347 this.loaded = true;
32348 this.ui.afterLoad(this);
32349 this.fireEvent("load", this);
32350 this.expand(deep, anim, callback);
32354 * Returns true if this node has been loaded
32355 * @return {Boolean}
32357 isLoaded : function(){
32358 return this.loaded;
32361 hasChildNodes : function(){
32362 if(!this.isLeaf() && !this.loaded){
32365 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32370 * Trigger a reload for this node
32371 * @param {Function} callback
32373 reload : function(callback){
32374 this.collapse(false, false);
32375 while(this.firstChild){
32376 this.removeChild(this.firstChild);
32378 this.childrenRendered = false;
32379 this.loaded = false;
32380 if(this.isHiddenRoot()){
32381 this.expanded = false;
32383 this.expand(false, false, callback);
32387 * Ext JS Library 1.1.1
32388 * Copyright(c) 2006-2007, Ext JS, LLC.
32390 * Originally Released Under LGPL - original licence link has changed is not relivant.
32393 * <script type="text/javascript">
32397 * @class Roo.tree.TreeNodeUI
32399 * @param {Object} node The node to render
32400 * The TreeNode UI implementation is separate from the
32401 * tree implementation. Unless you are customizing the tree UI,
32402 * you should never have to use this directly.
32404 Roo.tree.TreeNodeUI = function(node){
32406 this.rendered = false;
32407 this.animating = false;
32408 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32411 Roo.tree.TreeNodeUI.prototype = {
32412 removeChild : function(node){
32414 this.ctNode.removeChild(node.ui.getEl());
32418 beforeLoad : function(){
32419 this.addClass("x-tree-node-loading");
32422 afterLoad : function(){
32423 this.removeClass("x-tree-node-loading");
32426 onTextChange : function(node, text, oldText){
32428 this.textNode.innerHTML = text;
32432 onDisableChange : function(node, state){
32433 this.disabled = state;
32435 this.addClass("x-tree-node-disabled");
32437 this.removeClass("x-tree-node-disabled");
32441 onSelectedChange : function(state){
32444 this.addClass("x-tree-selected");
32447 this.removeClass("x-tree-selected");
32451 onMove : function(tree, node, oldParent, newParent, index, refNode){
32452 this.childIndent = null;
32454 var targetNode = newParent.ui.getContainer();
32455 if(!targetNode){//target not rendered
32456 this.holder = document.createElement("div");
32457 this.holder.appendChild(this.wrap);
32460 var insertBefore = refNode ? refNode.ui.getEl() : null;
32462 targetNode.insertBefore(this.wrap, insertBefore);
32464 targetNode.appendChild(this.wrap);
32466 this.node.renderIndent(true);
32470 addClass : function(cls){
32472 Roo.fly(this.elNode).addClass(cls);
32476 removeClass : function(cls){
32478 Roo.fly(this.elNode).removeClass(cls);
32482 remove : function(){
32484 this.holder = document.createElement("div");
32485 this.holder.appendChild(this.wrap);
32489 fireEvent : function(){
32490 return this.node.fireEvent.apply(this.node, arguments);
32493 initEvents : function(){
32494 this.node.on("move", this.onMove, this);
32495 var E = Roo.EventManager;
32496 var a = this.anchor;
32498 var el = Roo.fly(a, '_treeui');
32500 if(Roo.isOpera){ // opera render bug ignores the CSS
32501 el.setStyle("text-decoration", "none");
32504 el.on("click", this.onClick, this);
32505 el.on("dblclick", this.onDblClick, this);
32508 Roo.EventManager.on(this.checkbox,
32509 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32512 el.on("contextmenu", this.onContextMenu, this);
32514 var icon = Roo.fly(this.iconNode);
32515 icon.on("click", this.onClick, this);
32516 icon.on("dblclick", this.onDblClick, this);
32517 icon.on("contextmenu", this.onContextMenu, this);
32518 E.on(this.ecNode, "click", this.ecClick, this, true);
32520 if(this.node.disabled){
32521 this.addClass("x-tree-node-disabled");
32523 if(this.node.hidden){
32524 this.addClass("x-tree-node-disabled");
32526 var ot = this.node.getOwnerTree();
32527 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32528 if(dd && (!this.node.isRoot || ot.rootVisible)){
32529 Roo.dd.Registry.register(this.elNode, {
32531 handles: this.getDDHandles(),
32537 getDDHandles : function(){
32538 return [this.iconNode, this.textNode];
32543 this.wrap.style.display = "none";
32549 this.wrap.style.display = "";
32553 onContextMenu : function(e){
32554 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32555 e.preventDefault();
32557 this.fireEvent("contextmenu", this.node, e);
32561 onClick : function(e){
32566 if(this.fireEvent("beforeclick", this.node, e) !== false){
32567 if(!this.disabled && this.node.attributes.href){
32568 this.fireEvent("click", this.node, e);
32571 e.preventDefault();
32576 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32577 this.node.toggle();
32580 this.fireEvent("click", this.node, e);
32586 onDblClick : function(e){
32587 e.preventDefault();
32592 this.toggleCheck();
32594 if(!this.animating && this.node.hasChildNodes()){
32595 this.node.toggle();
32597 this.fireEvent("dblclick", this.node, e);
32600 onCheckChange : function(){
32601 var checked = this.checkbox.checked;
32602 this.node.attributes.checked = checked;
32603 this.fireEvent('checkchange', this.node, checked);
32606 ecClick : function(e){
32607 if(!this.animating && this.node.hasChildNodes()){
32608 this.node.toggle();
32612 startDrop : function(){
32613 this.dropping = true;
32616 // delayed drop so the click event doesn't get fired on a drop
32617 endDrop : function(){
32618 setTimeout(function(){
32619 this.dropping = false;
32620 }.createDelegate(this), 50);
32623 expand : function(){
32624 this.updateExpandIcon();
32625 this.ctNode.style.display = "";
32628 focus : function(){
32629 if(!this.node.preventHScroll){
32630 try{this.anchor.focus();
32632 }else if(!Roo.isIE){
32634 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32635 var l = noscroll.scrollLeft;
32636 this.anchor.focus();
32637 noscroll.scrollLeft = l;
32642 toggleCheck : function(value){
32643 var cb = this.checkbox;
32645 cb.checked = (value === undefined ? !cb.checked : value);
32651 this.anchor.blur();
32655 animExpand : function(callback){
32656 var ct = Roo.get(this.ctNode);
32658 if(!this.node.hasChildNodes()){
32659 this.updateExpandIcon();
32660 this.ctNode.style.display = "";
32661 Roo.callback(callback);
32664 this.animating = true;
32665 this.updateExpandIcon();
32668 callback : function(){
32669 this.animating = false;
32670 Roo.callback(callback);
32673 duration: this.node.ownerTree.duration || .25
32677 highlight : function(){
32678 var tree = this.node.getOwnerTree();
32679 Roo.fly(this.wrap).highlight(
32680 tree.hlColor || "C3DAF9",
32681 {endColor: tree.hlBaseColor}
32685 collapse : function(){
32686 this.updateExpandIcon();
32687 this.ctNode.style.display = "none";
32690 animCollapse : function(callback){
32691 var ct = Roo.get(this.ctNode);
32692 ct.enableDisplayMode('block');
32695 this.animating = true;
32696 this.updateExpandIcon();
32699 callback : function(){
32700 this.animating = false;
32701 Roo.callback(callback);
32704 duration: this.node.ownerTree.duration || .25
32708 getContainer : function(){
32709 return this.ctNode;
32712 getEl : function(){
32716 appendDDGhost : function(ghostNode){
32717 ghostNode.appendChild(this.elNode.cloneNode(true));
32720 getDDRepairXY : function(){
32721 return Roo.lib.Dom.getXY(this.iconNode);
32724 onRender : function(){
32728 render : function(bulkRender){
32729 var n = this.node, a = n.attributes;
32730 var targetNode = n.parentNode ?
32731 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32733 if(!this.rendered){
32734 this.rendered = true;
32736 this.renderElements(n, a, targetNode, bulkRender);
32739 if(this.textNode.setAttributeNS){
32740 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32742 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32745 this.textNode.setAttribute("ext:qtip", a.qtip);
32747 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32750 }else if(a.qtipCfg){
32751 a.qtipCfg.target = Roo.id(this.textNode);
32752 Roo.QuickTips.register(a.qtipCfg);
32755 if(!this.node.expanded){
32756 this.updateExpandIcon();
32759 if(bulkRender === true) {
32760 targetNode.appendChild(this.wrap);
32765 renderElements : function(n, a, targetNode, bulkRender)
32767 // add some indent caching, this helps performance when rendering a large tree
32768 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32769 var t = n.getOwnerTree();
32770 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32771 if (typeof(n.attributes.html) != 'undefined') {
32772 txt = n.attributes.html;
32774 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32775 var cb = typeof a.checked == 'boolean';
32776 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32777 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32778 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32779 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32780 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32781 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32782 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32783 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32784 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32785 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32788 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32789 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32790 n.nextSibling.ui.getEl(), buf.join(""));
32792 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32795 this.elNode = this.wrap.childNodes[0];
32796 this.ctNode = this.wrap.childNodes[1];
32797 var cs = this.elNode.childNodes;
32798 this.indentNode = cs[0];
32799 this.ecNode = cs[1];
32800 this.iconNode = cs[2];
32803 this.checkbox = cs[3];
32806 this.anchor = cs[index];
32807 this.textNode = cs[index].firstChild;
32810 getAnchor : function(){
32811 return this.anchor;
32814 getTextEl : function(){
32815 return this.textNode;
32818 getIconEl : function(){
32819 return this.iconNode;
32822 isChecked : function(){
32823 return this.checkbox ? this.checkbox.checked : false;
32826 updateExpandIcon : function(){
32828 var n = this.node, c1, c2;
32829 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32830 var hasChild = n.hasChildNodes();
32834 c1 = "x-tree-node-collapsed";
32835 c2 = "x-tree-node-expanded";
32838 c1 = "x-tree-node-expanded";
32839 c2 = "x-tree-node-collapsed";
32842 this.removeClass("x-tree-node-leaf");
32843 this.wasLeaf = false;
32845 if(this.c1 != c1 || this.c2 != c2){
32846 Roo.fly(this.elNode).replaceClass(c1, c2);
32847 this.c1 = c1; this.c2 = c2;
32850 // this changes non-leafs into leafs if they have no children.
32851 // it's not very rational behaviour..
32853 if(!this.wasLeaf && this.node.leaf){
32854 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32857 this.wasLeaf = true;
32860 var ecc = "x-tree-ec-icon "+cls;
32861 if(this.ecc != ecc){
32862 this.ecNode.className = ecc;
32868 getChildIndent : function(){
32869 if(!this.childIndent){
32873 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32875 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32877 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32882 this.childIndent = buf.join("");
32884 return this.childIndent;
32887 renderIndent : function(){
32890 var p = this.node.parentNode;
32892 indent = p.ui.getChildIndent();
32894 if(this.indentMarkup != indent){ // don't rerender if not required
32895 this.indentNode.innerHTML = indent;
32896 this.indentMarkup = indent;
32898 this.updateExpandIcon();
32903 Roo.tree.RootTreeNodeUI = function(){
32904 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32906 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32907 render : function(){
32908 if(!this.rendered){
32909 var targetNode = this.node.ownerTree.innerCt.dom;
32910 this.node.expanded = true;
32911 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32912 this.wrap = this.ctNode = targetNode.firstChild;
32915 collapse : function(){
32917 expand : function(){
32921 * Ext JS Library 1.1.1
32922 * Copyright(c) 2006-2007, Ext JS, LLC.
32924 * Originally Released Under LGPL - original licence link has changed is not relivant.
32927 * <script type="text/javascript">
32930 * @class Roo.tree.TreeLoader
32931 * @extends Roo.util.Observable
32932 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32933 * nodes from a specified URL. The response must be a javascript Array definition
32934 * who's elements are node definition objects. eg:
32939 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
32940 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
32947 * The old style respose with just an array is still supported, but not recommended.
32950 * A server request is sent, and child nodes are loaded only when a node is expanded.
32951 * The loading node's id is passed to the server under the parameter name "node" to
32952 * enable the server to produce the correct child nodes.
32954 * To pass extra parameters, an event handler may be attached to the "beforeload"
32955 * event, and the parameters specified in the TreeLoader's baseParams property:
32957 myTreeLoader.on("beforeload", function(treeLoader, node) {
32958 this.baseParams.category = node.attributes.category;
32961 * This would pass an HTTP parameter called "category" to the server containing
32962 * the value of the Node's "category" attribute.
32964 * Creates a new Treeloader.
32965 * @param {Object} config A config object containing config properties.
32967 Roo.tree.TreeLoader = function(config){
32968 this.baseParams = {};
32969 this.requestMethod = "POST";
32970 Roo.apply(this, config);
32975 * @event beforeload
32976 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32977 * @param {Object} This TreeLoader object.
32978 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32979 * @param {Object} callback The callback function specified in the {@link #load} call.
32984 * Fires when the node has been successfuly loaded.
32985 * @param {Object} This TreeLoader object.
32986 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32987 * @param {Object} response The response object containing the data from the server.
32991 * @event loadexception
32992 * Fires if the network request failed.
32993 * @param {Object} This TreeLoader object.
32994 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32995 * @param {Object} response The response object containing the data from the server.
32997 loadexception : true,
33000 * Fires before a node is created, enabling you to return custom Node types
33001 * @param {Object} This TreeLoader object.
33002 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33007 Roo.tree.TreeLoader.superclass.constructor.call(this);
33010 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33012 * @cfg {String} dataUrl The URL from which to request a Json string which
33013 * specifies an array of node definition object representing the child nodes
33017 * @cfg {Object} baseParams (optional) An object containing properties which
33018 * specify HTTP parameters to be passed to each request for child nodes.
33021 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33022 * created by this loader. If the attributes sent by the server have an attribute in this object,
33023 * they take priority.
33026 * @cfg {Object} uiProviders (optional) An object containing properties which
33028 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33029 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33030 * <i>uiProvider</i> attribute of a returned child node is a string rather
33031 * than a reference to a TreeNodeUI implementation, this that string value
33032 * is used as a property name in the uiProviders object. You can define the provider named
33033 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33038 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33039 * child nodes before loading.
33041 clearOnLoad : true,
33044 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33045 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33046 * Grid query { data : [ .....] }
33051 * @cfg {String} queryParam (optional)
33052 * Name of the query as it will be passed on the querystring (defaults to 'node')
33053 * eg. the request will be ?node=[id]
33060 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33061 * This is called automatically when a node is expanded, but may be used to reload
33062 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33063 * @param {Roo.tree.TreeNode} node
33064 * @param {Function} callback
33066 load : function(node, callback){
33067 if(this.clearOnLoad){
33068 while(node.firstChild){
33069 node.removeChild(node.firstChild);
33072 if(node.attributes.children){ // preloaded json children
33073 var cs = node.attributes.children;
33074 for(var i = 0, len = cs.length; i < len; i++){
33075 node.appendChild(this.createNode(cs[i]));
33077 if(typeof callback == "function"){
33080 }else if(this.dataUrl){
33081 this.requestData(node, callback);
33085 getParams: function(node){
33086 var buf = [], bp = this.baseParams;
33087 for(var key in bp){
33088 if(typeof bp[key] != "function"){
33089 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33092 var n = this.queryParam === false ? 'node' : this.queryParam;
33093 buf.push(n + "=", encodeURIComponent(node.id));
33094 return buf.join("");
33097 requestData : function(node, callback){
33098 if(this.fireEvent("beforeload", this, node, callback) !== false){
33099 this.transId = Roo.Ajax.request({
33100 method:this.requestMethod,
33101 url: this.dataUrl||this.url,
33102 success: this.handleResponse,
33103 failure: this.handleFailure,
33105 argument: {callback: callback, node: node},
33106 params: this.getParams(node)
33109 // if the load is cancelled, make sure we notify
33110 // the node that we are done
33111 if(typeof callback == "function"){
33117 isLoading : function(){
33118 return this.transId ? true : false;
33121 abort : function(){
33122 if(this.isLoading()){
33123 Roo.Ajax.abort(this.transId);
33128 createNode : function(attr)
33130 // apply baseAttrs, nice idea Corey!
33131 if(this.baseAttrs){
33132 Roo.applyIf(attr, this.baseAttrs);
33134 if(this.applyLoader !== false){
33135 attr.loader = this;
33137 // uiProvider = depreciated..
33139 if(typeof(attr.uiProvider) == 'string'){
33140 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33141 /** eval:var:attr */ eval(attr.uiProvider);
33143 if(typeof(this.uiProviders['default']) != 'undefined') {
33144 attr.uiProvider = this.uiProviders['default'];
33147 this.fireEvent('create', this, attr);
33149 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33151 new Roo.tree.TreeNode(attr) :
33152 new Roo.tree.AsyncTreeNode(attr));
33155 processResponse : function(response, node, callback)
33157 var json = response.responseText;
33160 var o = Roo.decode(json);
33162 if (this.root === false && typeof(o.success) != undefined) {
33163 this.root = 'data'; // the default behaviour for list like data..
33166 if (this.root !== false && !o.success) {
33167 // it's a failure condition.
33168 var a = response.argument;
33169 this.fireEvent("loadexception", this, a.node, response);
33170 Roo.log("Load failed - should have a handler really");
33176 if (this.root !== false) {
33180 for(var i = 0, len = o.length; i < len; i++){
33181 var n = this.createNode(o[i]);
33183 node.appendChild(n);
33186 if(typeof callback == "function"){
33187 callback(this, node);
33190 this.handleFailure(response);
33194 handleResponse : function(response){
33195 this.transId = false;
33196 var a = response.argument;
33197 this.processResponse(response, a.node, a.callback);
33198 this.fireEvent("load", this, a.node, response);
33201 handleFailure : function(response)
33203 // should handle failure better..
33204 this.transId = false;
33205 var a = response.argument;
33206 this.fireEvent("loadexception", this, a.node, response);
33207 if(typeof a.callback == "function"){
33208 a.callback(this, a.node);
33213 * Ext JS Library 1.1.1
33214 * Copyright(c) 2006-2007, Ext JS, LLC.
33216 * Originally Released Under LGPL - original licence link has changed is not relivant.
33219 * <script type="text/javascript">
33223 * @class Roo.tree.TreeFilter
33224 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33225 * @param {TreePanel} tree
33226 * @param {Object} config (optional)
33228 Roo.tree.TreeFilter = function(tree, config){
33230 this.filtered = {};
33231 Roo.apply(this, config);
33234 Roo.tree.TreeFilter.prototype = {
33241 * Filter the data by a specific attribute.
33242 * @param {String/RegExp} value Either string that the attribute value
33243 * should start with or a RegExp to test against the attribute
33244 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33245 * @param {TreeNode} startNode (optional) The node to start the filter at.
33247 filter : function(value, attr, startNode){
33248 attr = attr || "text";
33250 if(typeof value == "string"){
33251 var vlen = value.length;
33252 // auto clear empty filter
33253 if(vlen == 0 && this.clearBlank){
33257 value = value.toLowerCase();
33259 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33261 }else if(value.exec){ // regex?
33263 return value.test(n.attributes[attr]);
33266 throw 'Illegal filter type, must be string or regex';
33268 this.filterBy(f, null, startNode);
33272 * Filter by a function. The passed function will be called with each
33273 * node in the tree (or from the startNode). If the function returns true, the node is kept
33274 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33275 * @param {Function} fn The filter function
33276 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33278 filterBy : function(fn, scope, startNode){
33279 startNode = startNode || this.tree.root;
33280 if(this.autoClear){
33283 var af = this.filtered, rv = this.reverse;
33284 var f = function(n){
33285 if(n == startNode){
33291 var m = fn.call(scope || n, n);
33299 startNode.cascade(f);
33302 if(typeof id != "function"){
33304 if(n && n.parentNode){
33305 n.parentNode.removeChild(n);
33313 * Clears the current filter. Note: with the "remove" option
33314 * set a filter cannot be cleared.
33316 clear : function(){
33318 var af = this.filtered;
33320 if(typeof id != "function"){
33327 this.filtered = {};
33332 * Ext JS Library 1.1.1
33333 * Copyright(c) 2006-2007, Ext JS, LLC.
33335 * Originally Released Under LGPL - original licence link has changed is not relivant.
33338 * <script type="text/javascript">
33343 * @class Roo.tree.TreeSorter
33344 * Provides sorting of nodes in a TreePanel
33346 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33347 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33348 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33349 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33350 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33351 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33353 * @param {TreePanel} tree
33354 * @param {Object} config
33356 Roo.tree.TreeSorter = function(tree, config){
33357 Roo.apply(this, config);
33358 tree.on("beforechildrenrendered", this.doSort, this);
33359 tree.on("append", this.updateSort, this);
33360 tree.on("insert", this.updateSort, this);
33362 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33363 var p = this.property || "text";
33364 var sortType = this.sortType;
33365 var fs = this.folderSort;
33366 var cs = this.caseSensitive === true;
33367 var leafAttr = this.leafAttr || 'leaf';
33369 this.sortFn = function(n1, n2){
33371 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33374 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33378 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33379 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33381 return dsc ? +1 : -1;
33383 return dsc ? -1 : +1;
33390 Roo.tree.TreeSorter.prototype = {
33391 doSort : function(node){
33392 node.sort(this.sortFn);
33395 compareNodes : function(n1, n2){
33396 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33399 updateSort : function(tree, node){
33400 if(node.childrenRendered){
33401 this.doSort.defer(1, this, [node]);
33406 * Ext JS Library 1.1.1
33407 * Copyright(c) 2006-2007, Ext JS, LLC.
33409 * Originally Released Under LGPL - original licence link has changed is not relivant.
33412 * <script type="text/javascript">
33415 if(Roo.dd.DropZone){
33417 Roo.tree.TreeDropZone = function(tree, config){
33418 this.allowParentInsert = false;
33419 this.allowContainerDrop = false;
33420 this.appendOnly = false;
33421 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33423 this.lastInsertClass = "x-tree-no-status";
33424 this.dragOverData = {};
33427 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33428 ddGroup : "TreeDD",
33430 expandDelay : 1000,
33432 expandNode : function(node){
33433 if(node.hasChildNodes() && !node.isExpanded()){
33434 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33438 queueExpand : function(node){
33439 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33442 cancelExpand : function(){
33443 if(this.expandProcId){
33444 clearTimeout(this.expandProcId);
33445 this.expandProcId = false;
33449 isValidDropPoint : function(n, pt, dd, e, data){
33450 if(!n || !data){ return false; }
33451 var targetNode = n.node;
33452 var dropNode = data.node;
33453 // default drop rules
33454 if(!(targetNode && targetNode.isTarget && pt)){
33457 if(pt == "append" && targetNode.allowChildren === false){
33460 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33463 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33466 // reuse the object
33467 var overEvent = this.dragOverData;
33468 overEvent.tree = this.tree;
33469 overEvent.target = targetNode;
33470 overEvent.data = data;
33471 overEvent.point = pt;
33472 overEvent.source = dd;
33473 overEvent.rawEvent = e;
33474 overEvent.dropNode = dropNode;
33475 overEvent.cancel = false;
33476 var result = this.tree.fireEvent("nodedragover", overEvent);
33477 return overEvent.cancel === false && result !== false;
33480 getDropPoint : function(e, n, dd){
33483 return tn.allowChildren !== false ? "append" : false; // always append for root
33485 var dragEl = n.ddel;
33486 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33487 var y = Roo.lib.Event.getPageY(e);
33488 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33490 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33491 var noAppend = tn.allowChildren === false;
33492 if(this.appendOnly || tn.parentNode.allowChildren === false){
33493 return noAppend ? false : "append";
33495 var noBelow = false;
33496 if(!this.allowParentInsert){
33497 noBelow = tn.hasChildNodes() && tn.isExpanded();
33499 var q = (b - t) / (noAppend ? 2 : 3);
33500 if(y >= t && y < (t + q)){
33502 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33509 onNodeEnter : function(n, dd, e, data){
33510 this.cancelExpand();
33513 onNodeOver : function(n, dd, e, data){
33514 var pt = this.getDropPoint(e, n, dd);
33517 // auto node expand check
33518 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33519 this.queueExpand(node);
33520 }else if(pt != "append"){
33521 this.cancelExpand();
33524 // set the insert point style on the target node
33525 var returnCls = this.dropNotAllowed;
33526 if(this.isValidDropPoint(n, pt, dd, e, data)){
33531 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33532 cls = "x-tree-drag-insert-above";
33533 }else if(pt == "below"){
33534 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33535 cls = "x-tree-drag-insert-below";
33537 returnCls = "x-tree-drop-ok-append";
33538 cls = "x-tree-drag-append";
33540 if(this.lastInsertClass != cls){
33541 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33542 this.lastInsertClass = cls;
33549 onNodeOut : function(n, dd, e, data){
33550 this.cancelExpand();
33551 this.removeDropIndicators(n);
33554 onNodeDrop : function(n, dd, e, data){
33555 var point = this.getDropPoint(e, n, dd);
33556 var targetNode = n.node;
33557 targetNode.ui.startDrop();
33558 if(!this.isValidDropPoint(n, point, dd, e, data)){
33559 targetNode.ui.endDrop();
33562 // first try to find the drop node
33563 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33566 target: targetNode,
33571 dropNode: dropNode,
33574 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33575 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33576 targetNode.ui.endDrop();
33579 // allow target changing
33580 targetNode = dropEvent.target;
33581 if(point == "append" && !targetNode.isExpanded()){
33582 targetNode.expand(false, null, function(){
33583 this.completeDrop(dropEvent);
33584 }.createDelegate(this));
33586 this.completeDrop(dropEvent);
33591 completeDrop : function(de){
33592 var ns = de.dropNode, p = de.point, t = de.target;
33593 if(!(ns instanceof Array)){
33597 for(var i = 0, len = ns.length; i < len; i++){
33600 t.parentNode.insertBefore(n, t);
33601 }else if(p == "below"){
33602 t.parentNode.insertBefore(n, t.nextSibling);
33608 if(this.tree.hlDrop){
33612 this.tree.fireEvent("nodedrop", de);
33615 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33616 if(this.tree.hlDrop){
33617 dropNode.ui.focus();
33618 dropNode.ui.highlight();
33620 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33623 getTree : function(){
33627 removeDropIndicators : function(n){
33630 Roo.fly(el).removeClass([
33631 "x-tree-drag-insert-above",
33632 "x-tree-drag-insert-below",
33633 "x-tree-drag-append"]);
33634 this.lastInsertClass = "_noclass";
33638 beforeDragDrop : function(target, e, id){
33639 this.cancelExpand();
33643 afterRepair : function(data){
33644 if(data && Roo.enableFx){
33645 data.node.ui.highlight();
33654 * Ext JS Library 1.1.1
33655 * Copyright(c) 2006-2007, Ext JS, LLC.
33657 * Originally Released Under LGPL - original licence link has changed is not relivant.
33660 * <script type="text/javascript">
33664 if(Roo.dd.DragZone){
33665 Roo.tree.TreeDragZone = function(tree, config){
33666 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33670 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33671 ddGroup : "TreeDD",
33673 onBeforeDrag : function(data, e){
33675 return n && n.draggable && !n.disabled;
33678 onInitDrag : function(e){
33679 var data = this.dragData;
33680 this.tree.getSelectionModel().select(data.node);
33681 this.proxy.update("");
33682 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33683 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33686 getRepairXY : function(e, data){
33687 return data.node.ui.getDDRepairXY();
33690 onEndDrag : function(data, e){
33691 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33694 onValidDrop : function(dd, e, id){
33695 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33699 beforeInvalidDrop : function(e, id){
33700 // this scrolls the original position back into view
33701 var sm = this.tree.getSelectionModel();
33702 sm.clearSelections();
33703 sm.select(this.dragData.node);
33708 * Ext JS Library 1.1.1
33709 * Copyright(c) 2006-2007, Ext JS, LLC.
33711 * Originally Released Under LGPL - original licence link has changed is not relivant.
33714 * <script type="text/javascript">
33717 * @class Roo.tree.TreeEditor
33718 * @extends Roo.Editor
33719 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33720 * as the editor field.
33722 * @param {Object} config (used to be the tree panel.)
33723 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33725 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
33726 * @cfg {Roo.form.TextField|Object} field The field configuration
33730 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
33733 if (oldconfig) { // old style..
33734 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
33737 tree = config.tree;
33738 config.field = config.field || {};
33739 config.field.xtype = 'TextField';
33740 field = Roo.factory(config.field, Roo.form);
33742 config = config || {};
33747 * @event beforenodeedit
33748 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
33749 * false from the handler of this event.
33750 * @param {Editor} this
33751 * @param {Roo.tree.Node} node
33753 "beforenodeedit" : true
33757 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
33761 tree.on('beforeclick', this.beforeNodeClick, this);
33762 tree.getTreeEl().on('mousedown', this.hide, this);
33763 this.on('complete', this.updateNode, this);
33764 this.on('beforestartedit', this.fitToTree, this);
33765 this.on('startedit', this.bindScroll, this, {delay:10});
33766 this.on('specialkey', this.onSpecialKey, this);
33769 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33771 * @cfg {String} alignment
33772 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33778 * @cfg {Boolean} hideEl
33779 * True to hide the bound element while the editor is displayed (defaults to false)
33783 * @cfg {String} cls
33784 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33786 cls: "x-small-editor x-tree-editor",
33788 * @cfg {Boolean} shim
33789 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33795 * @cfg {Number} maxWidth
33796 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33797 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33798 * scroll and client offsets into account prior to each edit.
33805 fitToTree : function(ed, el){
33806 var td = this.tree.getTreeEl().dom, nd = el.dom;
33807 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33808 td.scrollLeft = nd.offsetLeft;
33812 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33813 this.setSize(w, '');
33815 return this.fireEvent('beforenodeedit', this, this.editNode);
33820 triggerEdit : function(node){
33821 this.completeEdit();
33822 this.editNode = node;
33823 this.startEdit(node.ui.textNode, node.text);
33827 bindScroll : function(){
33828 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33832 beforeNodeClick : function(node, e){
33833 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33834 this.lastClick = new Date();
33835 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33837 this.triggerEdit(node);
33844 updateNode : function(ed, value){
33845 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33846 this.editNode.setText(value);
33850 onHide : function(){
33851 Roo.tree.TreeEditor.superclass.onHide.call(this);
33853 this.editNode.ui.focus();
33858 onSpecialKey : function(field, e){
33859 var k = e.getKey();
33863 }else if(k == e.ENTER && !e.hasModifier()){
33865 this.completeEdit();
33868 });//<Script type="text/javascript">
33871 * Ext JS Library 1.1.1
33872 * Copyright(c) 2006-2007, Ext JS, LLC.
33874 * Originally Released Under LGPL - original licence link has changed is not relivant.
33877 * <script type="text/javascript">
33881 * Not documented??? - probably should be...
33884 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33885 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33887 renderElements : function(n, a, targetNode, bulkRender){
33888 //consel.log("renderElements?");
33889 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33891 var t = n.getOwnerTree();
33892 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33894 var cols = t.columns;
33895 var bw = t.borderWidth;
33897 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33898 var cb = typeof a.checked == "boolean";
33899 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33900 var colcls = 'x-t-' + tid + '-c0';
33902 '<li class="x-tree-node">',
33905 '<div class="x-tree-node-el ', a.cls,'">',
33907 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33910 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33911 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33912 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33913 (a.icon ? ' x-tree-node-inline-icon' : ''),
33914 (a.iconCls ? ' '+a.iconCls : ''),
33915 '" unselectable="on" />',
33916 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33917 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33919 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33920 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33921 '<span unselectable="on" qtip="' + tx + '">',
33925 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33926 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33928 for(var i = 1, len = cols.length; i < len; i++){
33930 colcls = 'x-t-' + tid + '-c' +i;
33931 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33932 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33933 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33939 '<div class="x-clear"></div></div>',
33940 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33943 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33944 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33945 n.nextSibling.ui.getEl(), buf.join(""));
33947 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33949 var el = this.wrap.firstChild;
33951 this.elNode = el.firstChild;
33952 this.ranchor = el.childNodes[1];
33953 this.ctNode = this.wrap.childNodes[1];
33954 var cs = el.firstChild.childNodes;
33955 this.indentNode = cs[0];
33956 this.ecNode = cs[1];
33957 this.iconNode = cs[2];
33960 this.checkbox = cs[3];
33963 this.anchor = cs[index];
33965 this.textNode = cs[index].firstChild;
33967 //el.on("click", this.onClick, this);
33968 //el.on("dblclick", this.onDblClick, this);
33971 // console.log(this);
33973 initEvents : function(){
33974 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33977 var a = this.ranchor;
33979 var el = Roo.get(a);
33981 if(Roo.isOpera){ // opera render bug ignores the CSS
33982 el.setStyle("text-decoration", "none");
33985 el.on("click", this.onClick, this);
33986 el.on("dblclick", this.onDblClick, this);
33987 el.on("contextmenu", this.onContextMenu, this);
33991 /*onSelectedChange : function(state){
33994 this.addClass("x-tree-selected");
33997 this.removeClass("x-tree-selected");
34000 addClass : function(cls){
34002 Roo.fly(this.elRow).addClass(cls);
34008 removeClass : function(cls){
34010 Roo.fly(this.elRow).removeClass(cls);
34016 });//<Script type="text/javascript">
34020 * Ext JS Library 1.1.1
34021 * Copyright(c) 2006-2007, Ext JS, LLC.
34023 * Originally Released Under LGPL - original licence link has changed is not relivant.
34026 * <script type="text/javascript">
34031 * @class Roo.tree.ColumnTree
34032 * @extends Roo.data.TreePanel
34033 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34034 * @cfg {int} borderWidth compined right/left border allowance
34036 * @param {String/HTMLElement/Element} el The container element
34037 * @param {Object} config
34039 Roo.tree.ColumnTree = function(el, config)
34041 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34045 * Fire this event on a container when it resizes
34046 * @param {int} w Width
34047 * @param {int} h Height
34051 this.on('resize', this.onResize, this);
34054 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34058 borderWidth: Roo.isBorderBox ? 0 : 2,
34061 render : function(){
34062 // add the header.....
34064 Roo.tree.ColumnTree.superclass.render.apply(this);
34066 this.el.addClass('x-column-tree');
34068 this.headers = this.el.createChild(
34069 {cls:'x-tree-headers'},this.innerCt.dom);
34071 var cols = this.columns, c;
34072 var totalWidth = 0;
34074 var len = cols.length;
34075 for(var i = 0; i < len; i++){
34077 totalWidth += c.width;
34078 this.headEls.push(this.headers.createChild({
34079 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34081 cls:'x-tree-hd-text',
34084 style:'width:'+(c.width-this.borderWidth)+'px;'
34087 this.headers.createChild({cls:'x-clear'});
34088 // prevent floats from wrapping when clipped
34089 this.headers.setWidth(totalWidth);
34090 //this.innerCt.setWidth(totalWidth);
34091 this.innerCt.setStyle({ overflow: 'auto' });
34092 this.onResize(this.width, this.height);
34096 onResize : function(w,h)
34101 this.innerCt.setWidth(this.width);
34102 this.innerCt.setHeight(this.height-20);
34105 var cols = this.columns, c;
34106 var totalWidth = 0;
34108 var len = cols.length;
34109 for(var i = 0; i < len; i++){
34111 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34112 // it's the expander..
34113 expEl = this.headEls[i];
34116 totalWidth += c.width;
34120 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34122 this.headers.setWidth(w-20);
34131 * Ext JS Library 1.1.1
34132 * Copyright(c) 2006-2007, Ext JS, LLC.
34134 * Originally Released Under LGPL - original licence link has changed is not relivant.
34137 * <script type="text/javascript">
34141 * @class Roo.menu.Menu
34142 * @extends Roo.util.Observable
34143 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34144 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34146 * Creates a new Menu
34147 * @param {Object} config Configuration options
34149 Roo.menu.Menu = function(config){
34150 Roo.apply(this, config);
34151 this.id = this.id || Roo.id();
34154 * @event beforeshow
34155 * Fires before this menu is displayed
34156 * @param {Roo.menu.Menu} this
34160 * @event beforehide
34161 * Fires before this menu is hidden
34162 * @param {Roo.menu.Menu} this
34167 * Fires after this menu is displayed
34168 * @param {Roo.menu.Menu} this
34173 * Fires after this menu is hidden
34174 * @param {Roo.menu.Menu} this
34179 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34180 * @param {Roo.menu.Menu} this
34181 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34182 * @param {Roo.EventObject} e
34187 * Fires when the mouse is hovering over this menu
34188 * @param {Roo.menu.Menu} this
34189 * @param {Roo.EventObject} e
34190 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34195 * Fires when the mouse exits this menu
34196 * @param {Roo.menu.Menu} this
34197 * @param {Roo.EventObject} e
34198 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34203 * Fires when a menu item contained in this menu is clicked
34204 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34205 * @param {Roo.EventObject} e
34209 if (this.registerMenu) {
34210 Roo.menu.MenuMgr.register(this);
34213 var mis = this.items;
34214 this.items = new Roo.util.MixedCollection();
34216 this.add.apply(this, mis);
34220 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34222 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34226 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34227 * for bottom-right shadow (defaults to "sides")
34231 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34232 * this menu (defaults to "tl-tr?")
34234 subMenuAlign : "tl-tr?",
34236 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34237 * relative to its element of origin (defaults to "tl-bl?")
34239 defaultAlign : "tl-bl?",
34241 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34243 allowOtherMenus : false,
34245 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34247 registerMenu : true,
34252 render : function(){
34256 var el = this.el = new Roo.Layer({
34258 shadow:this.shadow,
34260 parentEl: this.parentEl || document.body,
34264 this.keyNav = new Roo.menu.MenuNav(this);
34267 el.addClass("x-menu-plain");
34270 el.addClass(this.cls);
34272 // generic focus element
34273 this.focusEl = el.createChild({
34274 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34276 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34277 ul.on("click", this.onClick, this);
34278 ul.on("mouseover", this.onMouseOver, this);
34279 ul.on("mouseout", this.onMouseOut, this);
34280 this.items.each(function(item){
34281 var li = document.createElement("li");
34282 li.className = "x-menu-list-item";
34283 ul.dom.appendChild(li);
34284 item.render(li, this);
34291 autoWidth : function(){
34292 var el = this.el, ul = this.ul;
34296 var w = this.width;
34299 }else if(Roo.isIE){
34300 el.setWidth(this.minWidth);
34301 var t = el.dom.offsetWidth; // force recalc
34302 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34307 delayAutoWidth : function(){
34310 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34312 this.awTask.delay(20);
34317 findTargetItem : function(e){
34318 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34319 if(t && t.menuItemId){
34320 return this.items.get(t.menuItemId);
34325 onClick : function(e){
34327 if(t = this.findTargetItem(e)){
34329 this.fireEvent("click", this, t, e);
34334 setActiveItem : function(item, autoExpand){
34335 if(item != this.activeItem){
34336 if(this.activeItem){
34337 this.activeItem.deactivate();
34339 this.activeItem = item;
34340 item.activate(autoExpand);
34341 }else if(autoExpand){
34347 tryActivate : function(start, step){
34348 var items = this.items;
34349 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34350 var item = items.get(i);
34351 if(!item.disabled && item.canActivate){
34352 this.setActiveItem(item, false);
34360 onMouseOver : function(e){
34362 if(t = this.findTargetItem(e)){
34363 if(t.canActivate && !t.disabled){
34364 this.setActiveItem(t, true);
34367 this.fireEvent("mouseover", this, e, t);
34371 onMouseOut : function(e){
34373 if(t = this.findTargetItem(e)){
34374 if(t == this.activeItem && t.shouldDeactivate(e)){
34375 this.activeItem.deactivate();
34376 delete this.activeItem;
34379 this.fireEvent("mouseout", this, e, t);
34383 * Read-only. Returns true if the menu is currently displayed, else false.
34386 isVisible : function(){
34387 return this.el && !this.hidden;
34391 * Displays this menu relative to another element
34392 * @param {String/HTMLElement/Roo.Element} element The element to align to
34393 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34394 * the element (defaults to this.defaultAlign)
34395 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34397 show : function(el, pos, parentMenu){
34398 this.parentMenu = parentMenu;
34402 this.fireEvent("beforeshow", this);
34403 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34407 * Displays this menu at a specific xy position
34408 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34409 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34411 showAt : function(xy, parentMenu, /* private: */_e){
34412 this.parentMenu = parentMenu;
34417 this.fireEvent("beforeshow", this);
34418 xy = this.el.adjustForConstraints(xy);
34422 this.hidden = false;
34424 this.fireEvent("show", this);
34427 focus : function(){
34429 this.doFocus.defer(50, this);
34433 doFocus : function(){
34435 this.focusEl.focus();
34440 * Hides this menu and optionally all parent menus
34441 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34443 hide : function(deep){
34444 if(this.el && this.isVisible()){
34445 this.fireEvent("beforehide", this);
34446 if(this.activeItem){
34447 this.activeItem.deactivate();
34448 this.activeItem = null;
34451 this.hidden = true;
34452 this.fireEvent("hide", this);
34454 if(deep === true && this.parentMenu){
34455 this.parentMenu.hide(true);
34460 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34461 * Any of the following are valid:
34463 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34464 * <li>An HTMLElement object which will be converted to a menu item</li>
34465 * <li>A menu item config object that will be created as a new menu item</li>
34466 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34467 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34472 var menu = new Roo.menu.Menu();
34474 // Create a menu item to add by reference
34475 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34477 // Add a bunch of items at once using different methods.
34478 // Only the last item added will be returned.
34479 var item = menu.add(
34480 menuItem, // add existing item by ref
34481 'Dynamic Item', // new TextItem
34482 '-', // new separator
34483 { text: 'Config Item' } // new item by config
34486 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34487 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34490 var a = arguments, l = a.length, item;
34491 for(var i = 0; i < l; i++){
34493 if ((typeof(el) == "object") && el.xtype && el.xns) {
34494 el = Roo.factory(el, Roo.menu);
34497 if(el.render){ // some kind of Item
34498 item = this.addItem(el);
34499 }else if(typeof el == "string"){ // string
34500 if(el == "separator" || el == "-"){
34501 item = this.addSeparator();
34503 item = this.addText(el);
34505 }else if(el.tagName || el.el){ // element
34506 item = this.addElement(el);
34507 }else if(typeof el == "object"){ // must be menu item config?
34508 item = this.addMenuItem(el);
34515 * Returns this menu's underlying {@link Roo.Element} object
34516 * @return {Roo.Element} The element
34518 getEl : function(){
34526 * Adds a separator bar to the menu
34527 * @return {Roo.menu.Item} The menu item that was added
34529 addSeparator : function(){
34530 return this.addItem(new Roo.menu.Separator());
34534 * Adds an {@link Roo.Element} object to the menu
34535 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34536 * @return {Roo.menu.Item} The menu item that was added
34538 addElement : function(el){
34539 return this.addItem(new Roo.menu.BaseItem(el));
34543 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34544 * @param {Roo.menu.Item} item The menu item to add
34545 * @return {Roo.menu.Item} The menu item that was added
34547 addItem : function(item){
34548 this.items.add(item);
34550 var li = document.createElement("li");
34551 li.className = "x-menu-list-item";
34552 this.ul.dom.appendChild(li);
34553 item.render(li, this);
34554 this.delayAutoWidth();
34560 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34561 * @param {Object} config A MenuItem config object
34562 * @return {Roo.menu.Item} The menu item that was added
34564 addMenuItem : function(config){
34565 if(!(config instanceof Roo.menu.Item)){
34566 if(typeof config.checked == "boolean"){ // must be check menu item config?
34567 config = new Roo.menu.CheckItem(config);
34569 config = new Roo.menu.Item(config);
34572 return this.addItem(config);
34576 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34577 * @param {String} text The text to display in the menu item
34578 * @return {Roo.menu.Item} The menu item that was added
34580 addText : function(text){
34581 return this.addItem(new Roo.menu.TextItem({ text : text }));
34585 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34586 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34587 * @param {Roo.menu.Item} item The menu item to add
34588 * @return {Roo.menu.Item} The menu item that was added
34590 insert : function(index, item){
34591 this.items.insert(index, item);
34593 var li = document.createElement("li");
34594 li.className = "x-menu-list-item";
34595 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34596 item.render(li, this);
34597 this.delayAutoWidth();
34603 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34604 * @param {Roo.menu.Item} item The menu item to remove
34606 remove : function(item){
34607 this.items.removeKey(item.id);
34612 * Removes and destroys all items in the menu
34614 removeAll : function(){
34616 while(f = this.items.first()){
34622 // MenuNav is a private utility class used internally by the Menu
34623 Roo.menu.MenuNav = function(menu){
34624 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34625 this.scope = this.menu = menu;
34628 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34629 doRelay : function(e, h){
34630 var k = e.getKey();
34631 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34632 this.menu.tryActivate(0, 1);
34635 return h.call(this.scope || this, e, this.menu);
34638 up : function(e, m){
34639 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34640 m.tryActivate(m.items.length-1, -1);
34644 down : function(e, m){
34645 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34646 m.tryActivate(0, 1);
34650 right : function(e, m){
34652 m.activeItem.expandMenu(true);
34656 left : function(e, m){
34658 if(m.parentMenu && m.parentMenu.activeItem){
34659 m.parentMenu.activeItem.activate();
34663 enter : function(e, m){
34665 e.stopPropagation();
34666 m.activeItem.onClick(e);
34667 m.fireEvent("click", this, m.activeItem);
34673 * Ext JS Library 1.1.1
34674 * Copyright(c) 2006-2007, Ext JS, LLC.
34676 * Originally Released Under LGPL - original licence link has changed is not relivant.
34679 * <script type="text/javascript">
34683 * @class Roo.menu.MenuMgr
34684 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34687 Roo.menu.MenuMgr = function(){
34688 var menus, active, groups = {}, attached = false, lastShow = new Date();
34690 // private - called when first menu is created
34693 active = new Roo.util.MixedCollection();
34694 Roo.get(document).addKeyListener(27, function(){
34695 if(active.length > 0){
34702 function hideAll(){
34703 if(active && active.length > 0){
34704 var c = active.clone();
34705 c.each(function(m){
34712 function onHide(m){
34714 if(active.length < 1){
34715 Roo.get(document).un("mousedown", onMouseDown);
34721 function onShow(m){
34722 var last = active.last();
34723 lastShow = new Date();
34726 Roo.get(document).on("mousedown", onMouseDown);
34730 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34731 m.parentMenu.activeChild = m;
34732 }else if(last && last.isVisible()){
34733 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34738 function onBeforeHide(m){
34740 m.activeChild.hide();
34742 if(m.autoHideTimer){
34743 clearTimeout(m.autoHideTimer);
34744 delete m.autoHideTimer;
34749 function onBeforeShow(m){
34750 var pm = m.parentMenu;
34751 if(!pm && !m.allowOtherMenus){
34753 }else if(pm && pm.activeChild && active != m){
34754 pm.activeChild.hide();
34759 function onMouseDown(e){
34760 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34766 function onBeforeCheck(mi, state){
34768 var g = groups[mi.group];
34769 for(var i = 0, l = g.length; i < l; i++){
34771 g[i].setChecked(false);
34780 * Hides all menus that are currently visible
34782 hideAll : function(){
34787 register : function(menu){
34791 menus[menu.id] = menu;
34792 menu.on("beforehide", onBeforeHide);
34793 menu.on("hide", onHide);
34794 menu.on("beforeshow", onBeforeShow);
34795 menu.on("show", onShow);
34796 var g = menu.group;
34797 if(g && menu.events["checkchange"]){
34801 groups[g].push(menu);
34802 menu.on("checkchange", onCheck);
34807 * Returns a {@link Roo.menu.Menu} object
34808 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34809 * be used to generate and return a new Menu instance.
34811 get : function(menu){
34812 if(typeof menu == "string"){ // menu id
34813 return menus[menu];
34814 }else if(menu.events){ // menu instance
34816 }else if(typeof menu.length == 'number'){ // array of menu items?
34817 return new Roo.menu.Menu({items:menu});
34818 }else{ // otherwise, must be a config
34819 return new Roo.menu.Menu(menu);
34824 unregister : function(menu){
34825 delete menus[menu.id];
34826 menu.un("beforehide", onBeforeHide);
34827 menu.un("hide", onHide);
34828 menu.un("beforeshow", onBeforeShow);
34829 menu.un("show", onShow);
34830 var g = menu.group;
34831 if(g && menu.events["checkchange"]){
34832 groups[g].remove(menu);
34833 menu.un("checkchange", onCheck);
34838 registerCheckable : function(menuItem){
34839 var g = menuItem.group;
34844 groups[g].push(menuItem);
34845 menuItem.on("beforecheckchange", onBeforeCheck);
34850 unregisterCheckable : function(menuItem){
34851 var g = menuItem.group;
34853 groups[g].remove(menuItem);
34854 menuItem.un("beforecheckchange", onBeforeCheck);
34860 * Ext JS Library 1.1.1
34861 * Copyright(c) 2006-2007, Ext JS, LLC.
34863 * Originally Released Under LGPL - original licence link has changed is not relivant.
34866 * <script type="text/javascript">
34871 * @class Roo.menu.BaseItem
34872 * @extends Roo.Component
34873 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34874 * management and base configuration options shared by all menu components.
34876 * Creates a new BaseItem
34877 * @param {Object} config Configuration options
34879 Roo.menu.BaseItem = function(config){
34880 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34885 * Fires when this item is clicked
34886 * @param {Roo.menu.BaseItem} this
34887 * @param {Roo.EventObject} e
34892 * Fires when this item is activated
34893 * @param {Roo.menu.BaseItem} this
34897 * @event deactivate
34898 * Fires when this item is deactivated
34899 * @param {Roo.menu.BaseItem} this
34905 this.on("click", this.handler, this.scope, true);
34909 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34911 * @cfg {Function} handler
34912 * A function that will handle the click event of this menu item (defaults to undefined)
34915 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34917 canActivate : false,
34919 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34921 activeClass : "x-menu-item-active",
34923 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34925 hideOnClick : true,
34927 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34932 ctype: "Roo.menu.BaseItem",
34935 actionMode : "container",
34938 render : function(container, parentMenu){
34939 this.parentMenu = parentMenu;
34940 Roo.menu.BaseItem.superclass.render.call(this, container);
34941 this.container.menuItemId = this.id;
34945 onRender : function(container, position){
34946 this.el = Roo.get(this.el);
34947 container.dom.appendChild(this.el.dom);
34951 onClick : function(e){
34952 if(!this.disabled && this.fireEvent("click", this, e) !== false
34953 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34954 this.handleClick(e);
34961 activate : function(){
34965 var li = this.container;
34966 li.addClass(this.activeClass);
34967 this.region = li.getRegion().adjust(2, 2, -2, -2);
34968 this.fireEvent("activate", this);
34973 deactivate : function(){
34974 this.container.removeClass(this.activeClass);
34975 this.fireEvent("deactivate", this);
34979 shouldDeactivate : function(e){
34980 return !this.region || !this.region.contains(e.getPoint());
34984 handleClick : function(e){
34985 if(this.hideOnClick){
34986 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34991 expandMenu : function(autoActivate){
34996 hideMenu : function(){
35001 * Ext JS Library 1.1.1
35002 * Copyright(c) 2006-2007, Ext JS, LLC.
35004 * Originally Released Under LGPL - original licence link has changed is not relivant.
35007 * <script type="text/javascript">
35011 * @class Roo.menu.Adapter
35012 * @extends Roo.menu.BaseItem
35013 * 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.
35014 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35016 * Creates a new Adapter
35017 * @param {Object} config Configuration options
35019 Roo.menu.Adapter = function(component, config){
35020 Roo.menu.Adapter.superclass.constructor.call(this, config);
35021 this.component = component;
35023 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35025 canActivate : true,
35028 onRender : function(container, position){
35029 this.component.render(container);
35030 this.el = this.component.getEl();
35034 activate : function(){
35038 this.component.focus();
35039 this.fireEvent("activate", this);
35044 deactivate : function(){
35045 this.fireEvent("deactivate", this);
35049 disable : function(){
35050 this.component.disable();
35051 Roo.menu.Adapter.superclass.disable.call(this);
35055 enable : function(){
35056 this.component.enable();
35057 Roo.menu.Adapter.superclass.enable.call(this);
35061 * Ext JS Library 1.1.1
35062 * Copyright(c) 2006-2007, Ext JS, LLC.
35064 * Originally Released Under LGPL - original licence link has changed is not relivant.
35067 * <script type="text/javascript">
35071 * @class Roo.menu.TextItem
35072 * @extends Roo.menu.BaseItem
35073 * Adds a static text string to a menu, usually used as either a heading or group separator.
35074 * Note: old style constructor with text is still supported.
35077 * Creates a new TextItem
35078 * @param {Object} cfg Configuration
35080 Roo.menu.TextItem = function(cfg){
35081 if (typeof(cfg) == 'string') {
35084 Roo.apply(this,cfg);
35087 Roo.menu.TextItem.superclass.constructor.call(this);
35090 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35092 * @cfg {Boolean} text Text to show on item.
35097 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35099 hideOnClick : false,
35101 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35103 itemCls : "x-menu-text",
35106 onRender : function(){
35107 var s = document.createElement("span");
35108 s.className = this.itemCls;
35109 s.innerHTML = this.text;
35111 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35115 * Ext JS Library 1.1.1
35116 * Copyright(c) 2006-2007, Ext JS, LLC.
35118 * Originally Released Under LGPL - original licence link has changed is not relivant.
35121 * <script type="text/javascript">
35125 * @class Roo.menu.Separator
35126 * @extends Roo.menu.BaseItem
35127 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35128 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35130 * @param {Object} config Configuration options
35132 Roo.menu.Separator = function(config){
35133 Roo.menu.Separator.superclass.constructor.call(this, config);
35136 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35138 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35140 itemCls : "x-menu-sep",
35142 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35144 hideOnClick : false,
35147 onRender : function(li){
35148 var s = document.createElement("span");
35149 s.className = this.itemCls;
35150 s.innerHTML = " ";
35152 li.addClass("x-menu-sep-li");
35153 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35157 * Ext JS Library 1.1.1
35158 * Copyright(c) 2006-2007, Ext JS, LLC.
35160 * Originally Released Under LGPL - original licence link has changed is not relivant.
35163 * <script type="text/javascript">
35166 * @class Roo.menu.Item
35167 * @extends Roo.menu.BaseItem
35168 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35169 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35170 * activation and click handling.
35172 * Creates a new Item
35173 * @param {Object} config Configuration options
35175 Roo.menu.Item = function(config){
35176 Roo.menu.Item.superclass.constructor.call(this, config);
35178 this.menu = Roo.menu.MenuMgr.get(this.menu);
35181 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35184 * @cfg {String} text
35185 * The text to show on the menu item.
35189 * @cfg {String} HTML to render in menu
35190 * The text to show on the menu item (HTML version).
35194 * @cfg {String} icon
35195 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35199 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35201 itemCls : "x-menu-item",
35203 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35205 canActivate : true,
35207 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35210 // doc'd in BaseItem
35214 ctype: "Roo.menu.Item",
35217 onRender : function(container, position){
35218 var el = document.createElement("a");
35219 el.hideFocus = true;
35220 el.unselectable = "on";
35221 el.href = this.href || "#";
35222 if(this.hrefTarget){
35223 el.target = this.hrefTarget;
35225 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35227 var html = this.html.length ? this.html : String.format('{0}',this.text);
35229 el.innerHTML = String.format(
35230 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35231 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35233 Roo.menu.Item.superclass.onRender.call(this, container, position);
35237 * Sets the text to display in this menu item
35238 * @param {String} text The text to display
35239 * @param {Boolean} isHTML true to indicate text is pure html.
35241 setText : function(text, isHTML){
35249 var html = this.html.length ? this.html : String.format('{0}',this.text);
35251 this.el.update(String.format(
35252 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35253 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35254 this.parentMenu.autoWidth();
35259 handleClick : function(e){
35260 if(!this.href){ // if no link defined, stop the event automatically
35263 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35267 activate : function(autoExpand){
35268 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35278 shouldDeactivate : function(e){
35279 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35280 if(this.menu && this.menu.isVisible()){
35281 return !this.menu.getEl().getRegion().contains(e.getPoint());
35289 deactivate : function(){
35290 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35295 expandMenu : function(autoActivate){
35296 if(!this.disabled && this.menu){
35297 clearTimeout(this.hideTimer);
35298 delete this.hideTimer;
35299 if(!this.menu.isVisible() && !this.showTimer){
35300 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35301 }else if (this.menu.isVisible() && autoActivate){
35302 this.menu.tryActivate(0, 1);
35308 deferExpand : function(autoActivate){
35309 delete this.showTimer;
35310 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35312 this.menu.tryActivate(0, 1);
35317 hideMenu : function(){
35318 clearTimeout(this.showTimer);
35319 delete this.showTimer;
35320 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35321 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35326 deferHide : function(){
35327 delete this.hideTimer;
35332 * Ext JS Library 1.1.1
35333 * Copyright(c) 2006-2007, Ext JS, LLC.
35335 * Originally Released Under LGPL - original licence link has changed is not relivant.
35338 * <script type="text/javascript">
35342 * @class Roo.menu.CheckItem
35343 * @extends Roo.menu.Item
35344 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35346 * Creates a new CheckItem
35347 * @param {Object} config Configuration options
35349 Roo.menu.CheckItem = function(config){
35350 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35353 * @event beforecheckchange
35354 * Fires before the checked value is set, providing an opportunity to cancel if needed
35355 * @param {Roo.menu.CheckItem} this
35356 * @param {Boolean} checked The new checked value that will be set
35358 "beforecheckchange" : true,
35360 * @event checkchange
35361 * Fires after the checked value has been set
35362 * @param {Roo.menu.CheckItem} this
35363 * @param {Boolean} checked The checked value that was set
35365 "checkchange" : true
35367 if(this.checkHandler){
35368 this.on('checkchange', this.checkHandler, this.scope);
35371 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35373 * @cfg {String} group
35374 * All check items with the same group name will automatically be grouped into a single-select
35375 * radio button group (defaults to '')
35378 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35380 itemCls : "x-menu-item x-menu-check-item",
35382 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35384 groupClass : "x-menu-group-item",
35387 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35388 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35389 * initialized with checked = true will be rendered as checked.
35394 ctype: "Roo.menu.CheckItem",
35397 onRender : function(c){
35398 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35400 this.el.addClass(this.groupClass);
35402 Roo.menu.MenuMgr.registerCheckable(this);
35404 this.checked = false;
35405 this.setChecked(true, true);
35410 destroy : function(){
35412 Roo.menu.MenuMgr.unregisterCheckable(this);
35414 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35418 * Set the checked state of this item
35419 * @param {Boolean} checked The new checked value
35420 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35422 setChecked : function(state, suppressEvent){
35423 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35424 if(this.container){
35425 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35427 this.checked = state;
35428 if(suppressEvent !== true){
35429 this.fireEvent("checkchange", this, state);
35435 handleClick : function(e){
35436 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35437 this.setChecked(!this.checked);
35439 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35443 * Ext JS Library 1.1.1
35444 * Copyright(c) 2006-2007, Ext JS, LLC.
35446 * Originally Released Under LGPL - original licence link has changed is not relivant.
35449 * <script type="text/javascript">
35453 * @class Roo.menu.DateItem
35454 * @extends Roo.menu.Adapter
35455 * A menu item that wraps the {@link Roo.DatPicker} component.
35457 * Creates a new DateItem
35458 * @param {Object} config Configuration options
35460 Roo.menu.DateItem = function(config){
35461 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35462 /** The Roo.DatePicker object @type Roo.DatePicker */
35463 this.picker = this.component;
35464 this.addEvents({select: true});
35466 this.picker.on("render", function(picker){
35467 picker.getEl().swallowEvent("click");
35468 picker.container.addClass("x-menu-date-item");
35471 this.picker.on("select", this.onSelect, this);
35474 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35476 onSelect : function(picker, date){
35477 this.fireEvent("select", this, date, picker);
35478 Roo.menu.DateItem.superclass.handleClick.call(this);
35482 * Ext JS Library 1.1.1
35483 * Copyright(c) 2006-2007, Ext JS, LLC.
35485 * Originally Released Under LGPL - original licence link has changed is not relivant.
35488 * <script type="text/javascript">
35492 * @class Roo.menu.ColorItem
35493 * @extends Roo.menu.Adapter
35494 * A menu item that wraps the {@link Roo.ColorPalette} component.
35496 * Creates a new ColorItem
35497 * @param {Object} config Configuration options
35499 Roo.menu.ColorItem = function(config){
35500 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35501 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35502 this.palette = this.component;
35503 this.relayEvents(this.palette, ["select"]);
35504 if(this.selectHandler){
35505 this.on('select', this.selectHandler, this.scope);
35508 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35510 * Ext JS Library 1.1.1
35511 * Copyright(c) 2006-2007, Ext JS, LLC.
35513 * Originally Released Under LGPL - original licence link has changed is not relivant.
35516 * <script type="text/javascript">
35521 * @class Roo.menu.DateMenu
35522 * @extends Roo.menu.Menu
35523 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35525 * Creates a new DateMenu
35526 * @param {Object} config Configuration options
35528 Roo.menu.DateMenu = function(config){
35529 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35531 var di = new Roo.menu.DateItem(config);
35534 * The {@link Roo.DatePicker} instance for this DateMenu
35537 this.picker = di.picker;
35540 * @param {DatePicker} picker
35541 * @param {Date} date
35543 this.relayEvents(di, ["select"]);
35545 this.on('beforeshow', function(){
35547 this.picker.hideMonthPicker(true);
35551 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35555 * Ext JS Library 1.1.1
35556 * Copyright(c) 2006-2007, Ext JS, LLC.
35558 * Originally Released Under LGPL - original licence link has changed is not relivant.
35561 * <script type="text/javascript">
35566 * @class Roo.menu.ColorMenu
35567 * @extends Roo.menu.Menu
35568 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35570 * Creates a new ColorMenu
35571 * @param {Object} config Configuration options
35573 Roo.menu.ColorMenu = function(config){
35574 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35576 var ci = new Roo.menu.ColorItem(config);
35579 * The {@link Roo.ColorPalette} instance for this ColorMenu
35580 * @type ColorPalette
35582 this.palette = ci.palette;
35585 * @param {ColorPalette} palette
35586 * @param {String} color
35588 this.relayEvents(ci, ["select"]);
35590 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35592 * Ext JS Library 1.1.1
35593 * Copyright(c) 2006-2007, Ext JS, LLC.
35595 * Originally Released Under LGPL - original licence link has changed is not relivant.
35598 * <script type="text/javascript">
35602 * @class Roo.form.Field
35603 * @extends Roo.BoxComponent
35604 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35606 * Creates a new Field
35607 * @param {Object} config Configuration options
35609 Roo.form.Field = function(config){
35610 Roo.form.Field.superclass.constructor.call(this, config);
35613 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35615 * @cfg {String} fieldLabel Label to use when rendering a form.
35618 * @cfg {String} qtip Mouse over tip
35622 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35624 invalidClass : "x-form-invalid",
35626 * @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")
35628 invalidText : "The value in this field is invalid",
35630 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35632 focusClass : "x-form-focus",
35634 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35635 automatic validation (defaults to "keyup").
35637 validationEvent : "keyup",
35639 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35641 validateOnBlur : true,
35643 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35645 validationDelay : 250,
35647 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35648 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35650 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35652 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35654 fieldClass : "x-form-field",
35656 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35659 ----------- ----------------------------------------------------------------------
35660 qtip Display a quick tip when the user hovers over the field
35661 title Display a default browser title attribute popup
35662 under Add a block div beneath the field containing the error text
35663 side Add an error icon to the right of the field with a popup on hover
35664 [element id] Add the error text directly to the innerHTML of the specified element
35667 msgTarget : 'qtip',
35669 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35674 * @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.
35679 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35684 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35686 inputType : undefined,
35689 * @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).
35691 tabIndex : undefined,
35694 isFormField : true,
35699 * @property {Roo.Element} fieldEl
35700 * Element Containing the rendered Field (with label etc.)
35703 * @cfg {Mixed} value A value to initialize this field with.
35708 * @cfg {String} name The field's HTML name attribute.
35711 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35715 initComponent : function(){
35716 Roo.form.Field.superclass.initComponent.call(this);
35720 * Fires when this field receives input focus.
35721 * @param {Roo.form.Field} this
35726 * Fires when this field loses input focus.
35727 * @param {Roo.form.Field} this
35731 * @event specialkey
35732 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35733 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35734 * @param {Roo.form.Field} this
35735 * @param {Roo.EventObject} e The event object
35740 * Fires just before the field blurs if the field value has changed.
35741 * @param {Roo.form.Field} this
35742 * @param {Mixed} newValue The new value
35743 * @param {Mixed} oldValue The original value
35748 * Fires after the field has been marked as invalid.
35749 * @param {Roo.form.Field} this
35750 * @param {String} msg The validation message
35755 * Fires after the field has been validated with no errors.
35756 * @param {Roo.form.Field} this
35761 * Fires after the key up
35762 * @param {Roo.form.Field} this
35763 * @param {Roo.EventObject} e The event Object
35770 * Returns the name attribute of the field if available
35771 * @return {String} name The field name
35773 getName: function(){
35774 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35778 onRender : function(ct, position){
35779 Roo.form.Field.superclass.onRender.call(this, ct, position);
35781 var cfg = this.getAutoCreate();
35783 cfg.name = this.name || this.id;
35785 if(this.inputType){
35786 cfg.type = this.inputType;
35788 this.el = ct.createChild(cfg, position);
35790 var type = this.el.dom.type;
35792 if(type == 'password'){
35795 this.el.addClass('x-form-'+type);
35798 this.el.dom.readOnly = true;
35800 if(this.tabIndex !== undefined){
35801 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35804 this.el.addClass([this.fieldClass, this.cls]);
35809 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35810 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35811 * @return {Roo.form.Field} this
35813 applyTo : function(target){
35814 this.allowDomMove = false;
35815 this.el = Roo.get(target);
35816 this.render(this.el.dom.parentNode);
35821 initValue : function(){
35822 if(this.value !== undefined){
35823 this.setValue(this.value);
35824 }else if(this.el.dom.value.length > 0){
35825 this.setValue(this.el.dom.value);
35830 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35832 isDirty : function() {
35833 if(this.disabled) {
35836 return String(this.getValue()) !== String(this.originalValue);
35840 afterRender : function(){
35841 Roo.form.Field.superclass.afterRender.call(this);
35846 fireKey : function(e){
35847 //Roo.log('field ' + e.getKey());
35848 if(e.isNavKeyPress()){
35849 this.fireEvent("specialkey", this, e);
35854 * Resets the current field value to the originally loaded value and clears any validation messages
35856 reset : function(){
35857 this.setValue(this.originalValue);
35858 this.clearInvalid();
35862 initEvents : function(){
35863 // safari killled keypress - so keydown is now used..
35864 this.el.on("keydown" , this.fireKey, this);
35865 this.el.on("focus", this.onFocus, this);
35866 this.el.on("blur", this.onBlur, this);
35867 this.el.relayEvent('keyup', this);
35869 // reference to original value for reset
35870 this.originalValue = this.getValue();
35874 onFocus : function(){
35875 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35876 this.el.addClass(this.focusClass);
35878 if(!this.hasFocus){
35879 this.hasFocus = true;
35880 this.startValue = this.getValue();
35881 this.fireEvent("focus", this);
35885 beforeBlur : Roo.emptyFn,
35888 onBlur : function(){
35890 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35891 this.el.removeClass(this.focusClass);
35893 this.hasFocus = false;
35894 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35897 var v = this.getValue();
35898 if(String(v) !== String(this.startValue)){
35899 this.fireEvent('change', this, v, this.startValue);
35901 this.fireEvent("blur", this);
35905 * Returns whether or not the field value is currently valid
35906 * @param {Boolean} preventMark True to disable marking the field invalid
35907 * @return {Boolean} True if the value is valid, else false
35909 isValid : function(preventMark){
35913 var restore = this.preventMark;
35914 this.preventMark = preventMark === true;
35915 var v = this.validateValue(this.processValue(this.getRawValue()));
35916 this.preventMark = restore;
35921 * Validates the field value
35922 * @return {Boolean} True if the value is valid, else false
35924 validate : function(){
35925 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35926 this.clearInvalid();
35932 processValue : function(value){
35937 // Subclasses should provide the validation implementation by overriding this
35938 validateValue : function(value){
35943 * Mark this field as invalid
35944 * @param {String} msg The validation message
35946 markInvalid : function(msg){
35947 if(!this.rendered || this.preventMark){ // not rendered
35950 this.el.addClass(this.invalidClass);
35951 msg = msg || this.invalidText;
35952 switch(this.msgTarget){
35954 this.el.dom.qtip = msg;
35955 this.el.dom.qclass = 'x-form-invalid-tip';
35956 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35957 Roo.QuickTips.enable();
35961 this.el.dom.title = msg;
35965 var elp = this.el.findParent('.x-form-element', 5, true);
35966 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35967 this.errorEl.setWidth(elp.getWidth(true)-20);
35969 this.errorEl.update(msg);
35970 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35973 if(!this.errorIcon){
35974 var elp = this.el.findParent('.x-form-element', 5, true);
35975 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35977 this.alignErrorIcon();
35978 this.errorIcon.dom.qtip = msg;
35979 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35980 this.errorIcon.show();
35981 this.on('resize', this.alignErrorIcon, this);
35984 var t = Roo.getDom(this.msgTarget);
35986 t.style.display = this.msgDisplay;
35989 this.fireEvent('invalid', this, msg);
35993 alignErrorIcon : function(){
35994 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35998 * Clear any invalid styles/messages for this field
36000 clearInvalid : function(){
36001 if(!this.rendered || this.preventMark){ // not rendered
36004 this.el.removeClass(this.invalidClass);
36005 switch(this.msgTarget){
36007 this.el.dom.qtip = '';
36010 this.el.dom.title = '';
36014 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36018 if(this.errorIcon){
36019 this.errorIcon.dom.qtip = '';
36020 this.errorIcon.hide();
36021 this.un('resize', this.alignErrorIcon, this);
36025 var t = Roo.getDom(this.msgTarget);
36027 t.style.display = 'none';
36030 this.fireEvent('valid', this);
36034 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36035 * @return {Mixed} value The field value
36037 getRawValue : function(){
36038 var v = this.el.getValue();
36039 if(v === this.emptyText){
36046 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36047 * @return {Mixed} value The field value
36049 getValue : function(){
36050 var v = this.el.getValue();
36051 if(v === this.emptyText || v === undefined){
36058 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36059 * @param {Mixed} value The value to set
36061 setRawValue : function(v){
36062 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36066 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36067 * @param {Mixed} value The value to set
36069 setValue : function(v){
36072 this.el.dom.value = (v === null || v === undefined ? '' : v);
36077 adjustSize : function(w, h){
36078 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36079 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36083 adjustWidth : function(tag, w){
36084 tag = tag.toLowerCase();
36085 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36086 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36087 if(tag == 'input'){
36090 if(tag = 'textarea'){
36093 }else if(Roo.isOpera){
36094 if(tag == 'input'){
36097 if(tag = 'textarea'){
36107 // anything other than normal should be considered experimental
36108 Roo.form.Field.msgFx = {
36110 show: function(msgEl, f){
36111 msgEl.setDisplayed('block');
36114 hide : function(msgEl, f){
36115 msgEl.setDisplayed(false).update('');
36120 show: function(msgEl, f){
36121 msgEl.slideIn('t', {stopFx:true});
36124 hide : function(msgEl, f){
36125 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36130 show: function(msgEl, f){
36131 msgEl.fixDisplay();
36132 msgEl.alignTo(f.el, 'tl-tr');
36133 msgEl.slideIn('l', {stopFx:true});
36136 hide : function(msgEl, f){
36137 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36142 * Ext JS Library 1.1.1
36143 * Copyright(c) 2006-2007, Ext JS, LLC.
36145 * Originally Released Under LGPL - original licence link has changed is not relivant.
36148 * <script type="text/javascript">
36153 * @class Roo.form.TextField
36154 * @extends Roo.form.Field
36155 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36156 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36158 * Creates a new TextField
36159 * @param {Object} config Configuration options
36161 Roo.form.TextField = function(config){
36162 Roo.form.TextField.superclass.constructor.call(this, config);
36166 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36167 * according to the default logic, but this event provides a hook for the developer to apply additional
36168 * logic at runtime to resize the field if needed.
36169 * @param {Roo.form.Field} this This text field
36170 * @param {Number} width The new field width
36176 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36178 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36182 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36186 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36190 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36194 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36198 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36200 disableKeyFilter : false,
36202 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36206 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36210 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36212 maxLength : Number.MAX_VALUE,
36214 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36216 minLengthText : "The minimum length for this field is {0}",
36218 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36220 maxLengthText : "The maximum length for this field is {0}",
36222 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36224 selectOnFocus : false,
36226 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36228 blankText : "This field is required",
36230 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36231 * If available, this function will be called only after the basic validators all return true, and will be passed the
36232 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36236 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36237 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36238 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36242 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36246 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36250 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36251 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36253 emptyClass : 'x-form-empty-field',
36256 initEvents : function(){
36257 Roo.form.TextField.superclass.initEvents.call(this);
36258 if(this.validationEvent == 'keyup'){
36259 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36260 this.el.on('keyup', this.filterValidation, this);
36262 else if(this.validationEvent !== false){
36263 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36265 if(this.selectOnFocus || this.emptyText){
36266 this.on("focus", this.preFocus, this);
36267 if(this.emptyText){
36268 this.on('blur', this.postBlur, this);
36269 this.applyEmptyText();
36272 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36273 this.el.on("keypress", this.filterKeys, this);
36276 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36277 this.el.on("click", this.autoSize, this);
36281 processValue : function(value){
36282 if(this.stripCharsRe){
36283 var newValue = value.replace(this.stripCharsRe, '');
36284 if(newValue !== value){
36285 this.setRawValue(newValue);
36292 filterValidation : function(e){
36293 if(!e.isNavKeyPress()){
36294 this.validationTask.delay(this.validationDelay);
36299 onKeyUp : function(e){
36300 if(!e.isNavKeyPress()){
36306 * Resets the current field value to the originally-loaded value and clears any validation messages.
36307 * Also adds emptyText and emptyClass if the original value was blank.
36309 reset : function(){
36310 Roo.form.TextField.superclass.reset.call(this);
36311 this.applyEmptyText();
36314 applyEmptyText : function(){
36315 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36316 this.setRawValue(this.emptyText);
36317 this.el.addClass(this.emptyClass);
36322 preFocus : function(){
36323 if(this.emptyText){
36324 if(this.el.dom.value == this.emptyText){
36325 this.setRawValue('');
36327 this.el.removeClass(this.emptyClass);
36329 if(this.selectOnFocus){
36330 this.el.dom.select();
36335 postBlur : function(){
36336 this.applyEmptyText();
36340 filterKeys : function(e){
36341 var k = e.getKey();
36342 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36345 var c = e.getCharCode(), cc = String.fromCharCode(c);
36346 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36349 if(!this.maskRe.test(cc)){
36354 setValue : function(v){
36355 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36356 this.el.removeClass(this.emptyClass);
36358 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36359 this.applyEmptyText();
36364 * Validates a value according to the field's validation rules and marks the field as invalid
36365 * if the validation fails
36366 * @param {Mixed} value The value to validate
36367 * @return {Boolean} True if the value is valid, else false
36369 validateValue : function(value){
36370 if(value.length < 1 || value === this.emptyText){ // if it's blank
36371 if(this.allowBlank){
36372 this.clearInvalid();
36375 this.markInvalid(this.blankText);
36379 if(value.length < this.minLength){
36380 this.markInvalid(String.format(this.minLengthText, this.minLength));
36383 if(value.length > this.maxLength){
36384 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36388 var vt = Roo.form.VTypes;
36389 if(!vt[this.vtype](value, this)){
36390 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36394 if(typeof this.validator == "function"){
36395 var msg = this.validator(value);
36397 this.markInvalid(msg);
36401 if(this.regex && !this.regex.test(value)){
36402 this.markInvalid(this.regexText);
36409 * Selects text in this field
36410 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36411 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36413 selectText : function(start, end){
36414 var v = this.getRawValue();
36416 start = start === undefined ? 0 : start;
36417 end = end === undefined ? v.length : end;
36418 var d = this.el.dom;
36419 if(d.setSelectionRange){
36420 d.setSelectionRange(start, end);
36421 }else if(d.createTextRange){
36422 var range = d.createTextRange();
36423 range.moveStart("character", start);
36424 range.moveEnd("character", v.length-end);
36431 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36432 * This only takes effect if grow = true, and fires the autosize event.
36434 autoSize : function(){
36435 if(!this.grow || !this.rendered){
36439 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36442 var v = el.dom.value;
36443 var d = document.createElement('div');
36444 d.appendChild(document.createTextNode(v));
36448 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36449 this.el.setWidth(w);
36450 this.fireEvent("autosize", this, w);
36454 * Ext JS Library 1.1.1
36455 * Copyright(c) 2006-2007, Ext JS, LLC.
36457 * Originally Released Under LGPL - original licence link has changed is not relivant.
36460 * <script type="text/javascript">
36464 * @class Roo.form.Hidden
36465 * @extends Roo.form.TextField
36466 * Simple Hidden element used on forms
36468 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36471 * Creates a new Hidden form element.
36472 * @param {Object} config Configuration options
36477 // easy hidden field...
36478 Roo.form.Hidden = function(config){
36479 Roo.form.Hidden.superclass.constructor.call(this, config);
36482 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36484 inputType: 'hidden',
36487 labelSeparator: '',
36489 itemCls : 'x-form-item-display-none'
36497 * Ext JS Library 1.1.1
36498 * Copyright(c) 2006-2007, Ext JS, LLC.
36500 * Originally Released Under LGPL - original licence link has changed is not relivant.
36503 * <script type="text/javascript">
36507 * @class Roo.form.TriggerField
36508 * @extends Roo.form.TextField
36509 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36510 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36511 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36512 * for which you can provide a custom implementation. For example:
36514 var trigger = new Roo.form.TriggerField();
36515 trigger.onTriggerClick = myTriggerFn;
36516 trigger.applyTo('my-field');
36519 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36520 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36521 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36522 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36524 * Create a new TriggerField.
36525 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36526 * to the base TextField)
36528 Roo.form.TriggerField = function(config){
36529 this.mimicing = false;
36530 Roo.form.TriggerField.superclass.constructor.call(this, config);
36533 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36535 * @cfg {String} triggerClass A CSS class to apply to the trigger
36538 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36539 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36541 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36543 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36547 /** @cfg {Boolean} grow @hide */
36548 /** @cfg {Number} growMin @hide */
36549 /** @cfg {Number} growMax @hide */
36555 autoSize: Roo.emptyFn,
36559 deferHeight : true,
36562 actionMode : 'wrap',
36564 onResize : function(w, h){
36565 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36566 if(typeof w == 'number'){
36567 var x = w - this.trigger.getWidth();
36568 this.el.setWidth(this.adjustWidth('input', x));
36569 this.trigger.setStyle('left', x+'px');
36574 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36577 getResizeEl : function(){
36582 getPositionEl : function(){
36587 alignErrorIcon : function(){
36588 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36592 onRender : function(ct, position){
36593 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36594 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36595 this.trigger = this.wrap.createChild(this.triggerConfig ||
36596 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36597 if(this.hideTrigger){
36598 this.trigger.setDisplayed(false);
36600 this.initTrigger();
36602 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36607 initTrigger : function(){
36608 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36609 this.trigger.addClassOnOver('x-form-trigger-over');
36610 this.trigger.addClassOnClick('x-form-trigger-click');
36614 onDestroy : function(){
36616 this.trigger.removeAllListeners();
36617 this.trigger.remove();
36620 this.wrap.remove();
36622 Roo.form.TriggerField.superclass.onDestroy.call(this);
36626 onFocus : function(){
36627 Roo.form.TriggerField.superclass.onFocus.call(this);
36628 if(!this.mimicing){
36629 this.wrap.addClass('x-trigger-wrap-focus');
36630 this.mimicing = true;
36631 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36632 if(this.monitorTab){
36633 this.el.on("keydown", this.checkTab, this);
36639 checkTab : function(e){
36640 if(e.getKey() == e.TAB){
36641 this.triggerBlur();
36646 onBlur : function(){
36651 mimicBlur : function(e, t){
36652 if(!this.wrap.contains(t) && this.validateBlur()){
36653 this.triggerBlur();
36658 triggerBlur : function(){
36659 this.mimicing = false;
36660 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36661 if(this.monitorTab){
36662 this.el.un("keydown", this.checkTab, this);
36664 this.wrap.removeClass('x-trigger-wrap-focus');
36665 Roo.form.TriggerField.superclass.onBlur.call(this);
36669 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36670 validateBlur : function(e, t){
36675 onDisable : function(){
36676 Roo.form.TriggerField.superclass.onDisable.call(this);
36678 this.wrap.addClass('x-item-disabled');
36683 onEnable : function(){
36684 Roo.form.TriggerField.superclass.onEnable.call(this);
36686 this.wrap.removeClass('x-item-disabled');
36691 onShow : function(){
36692 var ae = this.getActionEl();
36695 ae.dom.style.display = '';
36696 ae.dom.style.visibility = 'visible';
36702 onHide : function(){
36703 var ae = this.getActionEl();
36704 ae.dom.style.display = 'none';
36708 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36709 * by an implementing function.
36711 * @param {EventObject} e
36713 onTriggerClick : Roo.emptyFn
36716 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36717 // to be extended by an implementing class. For an example of implementing this class, see the custom
36718 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36719 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36720 initComponent : function(){
36721 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36723 this.triggerConfig = {
36724 tag:'span', cls:'x-form-twin-triggers', cn:[
36725 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36726 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36730 getTrigger : function(index){
36731 return this.triggers[index];
36734 initTrigger : function(){
36735 var ts = this.trigger.select('.x-form-trigger', true);
36736 this.wrap.setStyle('overflow', 'hidden');
36737 var triggerField = this;
36738 ts.each(function(t, all, index){
36739 t.hide = function(){
36740 var w = triggerField.wrap.getWidth();
36741 this.dom.style.display = 'none';
36742 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36744 t.show = function(){
36745 var w = triggerField.wrap.getWidth();
36746 this.dom.style.display = '';
36747 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36749 var triggerIndex = 'Trigger'+(index+1);
36751 if(this['hide'+triggerIndex]){
36752 t.dom.style.display = 'none';
36754 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36755 t.addClassOnOver('x-form-trigger-over');
36756 t.addClassOnClick('x-form-trigger-click');
36758 this.triggers = ts.elements;
36761 onTrigger1Click : Roo.emptyFn,
36762 onTrigger2Click : Roo.emptyFn
36765 * Ext JS Library 1.1.1
36766 * Copyright(c) 2006-2007, Ext JS, LLC.
36768 * Originally Released Under LGPL - original licence link has changed is not relivant.
36771 * <script type="text/javascript">
36775 * @class Roo.form.TextArea
36776 * @extends Roo.form.TextField
36777 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36778 * support for auto-sizing.
36780 * Creates a new TextArea
36781 * @param {Object} config Configuration options
36783 Roo.form.TextArea = function(config){
36784 Roo.form.TextArea.superclass.constructor.call(this, config);
36785 // these are provided exchanges for backwards compat
36786 // minHeight/maxHeight were replaced by growMin/growMax to be
36787 // compatible with TextField growing config values
36788 if(this.minHeight !== undefined){
36789 this.growMin = this.minHeight;
36791 if(this.maxHeight !== undefined){
36792 this.growMax = this.maxHeight;
36796 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36798 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36802 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36806 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36807 * in the field (equivalent to setting overflow: hidden, defaults to false)
36809 preventScrollbars: false,
36811 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36812 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36816 onRender : function(ct, position){
36818 this.defaultAutoCreate = {
36820 style:"width:300px;height:60px;",
36821 autocomplete: "off"
36824 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36826 this.textSizeEl = Roo.DomHelper.append(document.body, {
36827 tag: "pre", cls: "x-form-grow-sizer"
36829 if(this.preventScrollbars){
36830 this.el.setStyle("overflow", "hidden");
36832 this.el.setHeight(this.growMin);
36836 onDestroy : function(){
36837 if(this.textSizeEl){
36838 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36840 Roo.form.TextArea.superclass.onDestroy.call(this);
36844 onKeyUp : function(e){
36845 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36851 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36852 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36854 autoSize : function(){
36855 if(!this.grow || !this.textSizeEl){
36859 var v = el.dom.value;
36860 var ts = this.textSizeEl;
36863 ts.appendChild(document.createTextNode(v));
36866 Roo.fly(ts).setWidth(this.el.getWidth());
36868 v = "  ";
36871 v = v.replace(/\n/g, '<p> </p>');
36873 v += " \n ";
36876 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36877 if(h != this.lastHeight){
36878 this.lastHeight = h;
36879 this.el.setHeight(h);
36880 this.fireEvent("autosize", this, h);
36885 * Ext JS Library 1.1.1
36886 * Copyright(c) 2006-2007, Ext JS, LLC.
36888 * Originally Released Under LGPL - original licence link has changed is not relivant.
36891 * <script type="text/javascript">
36896 * @class Roo.form.NumberField
36897 * @extends Roo.form.TextField
36898 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36900 * Creates a new NumberField
36901 * @param {Object} config Configuration options
36903 Roo.form.NumberField = function(config){
36904 Roo.form.NumberField.superclass.constructor.call(this, config);
36907 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36909 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36911 fieldClass: "x-form-field x-form-num-field",
36913 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36915 allowDecimals : true,
36917 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36919 decimalSeparator : ".",
36921 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36923 decimalPrecision : 2,
36925 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36927 allowNegative : true,
36929 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36931 minValue : Number.NEGATIVE_INFINITY,
36933 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36935 maxValue : Number.MAX_VALUE,
36937 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36939 minText : "The minimum value for this field is {0}",
36941 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36943 maxText : "The maximum value for this field is {0}",
36945 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36946 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36948 nanText : "{0} is not a valid number",
36951 initEvents : function(){
36952 Roo.form.NumberField.superclass.initEvents.call(this);
36953 var allowed = "0123456789";
36954 if(this.allowDecimals){
36955 allowed += this.decimalSeparator;
36957 if(this.allowNegative){
36960 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36961 var keyPress = function(e){
36962 var k = e.getKey();
36963 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36966 var c = e.getCharCode();
36967 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36971 this.el.on("keypress", keyPress, this);
36975 validateValue : function(value){
36976 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36979 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36982 var num = this.parseValue(value);
36984 this.markInvalid(String.format(this.nanText, value));
36987 if(num < this.minValue){
36988 this.markInvalid(String.format(this.minText, this.minValue));
36991 if(num > this.maxValue){
36992 this.markInvalid(String.format(this.maxText, this.maxValue));
36998 getValue : function(){
36999 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37003 parseValue : function(value){
37004 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37005 return isNaN(value) ? '' : value;
37009 fixPrecision : function(value){
37010 var nan = isNaN(value);
37011 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37012 return nan ? '' : value;
37014 return parseFloat(value).toFixed(this.decimalPrecision);
37017 setValue : function(v){
37018 v = this.fixPrecision(v);
37019 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37023 decimalPrecisionFcn : function(v){
37024 return Math.floor(v);
37027 beforeBlur : function(){
37028 var v = this.parseValue(this.getRawValue());
37035 * Ext JS Library 1.1.1
37036 * Copyright(c) 2006-2007, Ext JS, LLC.
37038 * Originally Released Under LGPL - original licence link has changed is not relivant.
37041 * <script type="text/javascript">
37045 * @class Roo.form.DateField
37046 * @extends Roo.form.TriggerField
37047 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37049 * Create a new DateField
37050 * @param {Object} config
37052 Roo.form.DateField = function(config){
37053 Roo.form.DateField.superclass.constructor.call(this, config);
37059 * Fires when a date is selected
37060 * @param {Roo.form.DateField} combo This combo box
37061 * @param {Date} date The date selected
37068 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37069 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37070 this.ddMatch = null;
37071 if(this.disabledDates){
37072 var dd = this.disabledDates;
37074 for(var i = 0; i < dd.length; i++){
37076 if(i != dd.length-1) re += "|";
37078 this.ddMatch = new RegExp(re + ")");
37082 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37084 * @cfg {String} format
37085 * The default date format string which can be overriden for localization support. The format must be
37086 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37090 * @cfg {String} altFormats
37091 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37092 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37094 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37096 * @cfg {Array} disabledDays
37097 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37099 disabledDays : null,
37101 * @cfg {String} disabledDaysText
37102 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37104 disabledDaysText : "Disabled",
37106 * @cfg {Array} disabledDates
37107 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37108 * expression so they are very powerful. Some examples:
37110 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37111 * <li>["03/08", "09/16"] would disable those days for every year</li>
37112 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37113 * <li>["03/../2006"] would disable every day in March 2006</li>
37114 * <li>["^03"] would disable every day in every March</li>
37116 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37117 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37119 disabledDates : null,
37121 * @cfg {String} disabledDatesText
37122 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37124 disabledDatesText : "Disabled",
37126 * @cfg {Date/String} minValue
37127 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37128 * valid format (defaults to null).
37132 * @cfg {Date/String} maxValue
37133 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37134 * valid format (defaults to null).
37138 * @cfg {String} minText
37139 * The error text to display when the date in the cell is before minValue (defaults to
37140 * 'The date in this field must be after {minValue}').
37142 minText : "The date in this field must be equal to or after {0}",
37144 * @cfg {String} maxText
37145 * The error text to display when the date in the cell is after maxValue (defaults to
37146 * 'The date in this field must be before {maxValue}').
37148 maxText : "The date in this field must be equal to or before {0}",
37150 * @cfg {String} invalidText
37151 * The error text to display when the date in the field is invalid (defaults to
37152 * '{value} is not a valid date - it must be in the format {format}').
37154 invalidText : "{0} is not a valid date - it must be in the format {1}",
37156 * @cfg {String} triggerClass
37157 * An additional CSS class used to style the trigger button. The trigger will always get the
37158 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37159 * which displays a calendar icon).
37161 triggerClass : 'x-form-date-trigger',
37165 * @cfg {bool} useIso
37166 * if enabled, then the date field will use a hidden field to store the
37167 * real value as iso formated date. default (false)
37171 * @cfg {String/Object} autoCreate
37172 * A DomHelper element spec, or true for a default element spec (defaults to
37173 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37176 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37179 hiddenField: false,
37181 onRender : function(ct, position)
37183 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37185 this.el.dom.removeAttribute('name');
37186 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37188 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
37189 // prevent input submission
37190 this.hiddenName = this.name;
37197 validateValue : function(value)
37199 value = this.formatDate(value);
37200 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37203 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37206 var svalue = value;
37207 value = this.parseDate(value);
37209 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37212 var time = value.getTime();
37213 if(this.minValue && time < this.minValue.getTime()){
37214 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37217 if(this.maxValue && time > this.maxValue.getTime()){
37218 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37221 if(this.disabledDays){
37222 var day = value.getDay();
37223 for(var i = 0; i < this.disabledDays.length; i++) {
37224 if(day === this.disabledDays[i]){
37225 this.markInvalid(this.disabledDaysText);
37230 var fvalue = this.formatDate(value);
37231 if(this.ddMatch && this.ddMatch.test(fvalue)){
37232 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37239 // Provides logic to override the default TriggerField.validateBlur which just returns true
37240 validateBlur : function(){
37241 return !this.menu || !this.menu.isVisible();
37245 * Returns the current date value of the date field.
37246 * @return {Date} The date value
37248 getValue : function(){
37250 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37254 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37255 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37256 * (the default format used is "m/d/y").
37259 //All of these calls set the same date value (May 4, 2006)
37261 //Pass a date object:
37262 var dt = new Date('5/4/06');
37263 dateField.setValue(dt);
37265 //Pass a date string (default format):
37266 dateField.setValue('5/4/06');
37268 //Pass a date string (custom format):
37269 dateField.format = 'Y-m-d';
37270 dateField.setValue('2006-5-4');
37272 * @param {String/Date} date The date or valid date string
37274 setValue : function(date){
37275 if (this.hiddenField) {
37276 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37278 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37282 parseDate : function(value){
37283 if(!value || value instanceof Date){
37286 var v = Date.parseDate(value, this.format);
37287 if(!v && this.altFormats){
37288 if(!this.altFormatsArray){
37289 this.altFormatsArray = this.altFormats.split("|");
37291 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37292 v = Date.parseDate(value, this.altFormatsArray[i]);
37299 formatDate : function(date, fmt){
37300 return (!date || !(date instanceof Date)) ?
37301 date : date.dateFormat(fmt || this.format);
37306 select: function(m, d){
37308 this.fireEvent('select', this, d);
37310 show : function(){ // retain focus styling
37314 this.focus.defer(10, this);
37315 var ml = this.menuListeners;
37316 this.menu.un("select", ml.select, this);
37317 this.menu.un("show", ml.show, this);
37318 this.menu.un("hide", ml.hide, this);
37323 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37324 onTriggerClick : function(){
37328 if(this.menu == null){
37329 this.menu = new Roo.menu.DateMenu();
37331 Roo.apply(this.menu.picker, {
37332 showClear: this.allowBlank,
37333 minDate : this.minValue,
37334 maxDate : this.maxValue,
37335 disabledDatesRE : this.ddMatch,
37336 disabledDatesText : this.disabledDatesText,
37337 disabledDays : this.disabledDays,
37338 disabledDaysText : this.disabledDaysText,
37339 format : this.format,
37340 minText : String.format(this.minText, this.formatDate(this.minValue)),
37341 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37343 this.menu.on(Roo.apply({}, this.menuListeners, {
37346 this.menu.picker.setValue(this.getValue() || new Date());
37347 this.menu.show(this.el, "tl-bl?");
37350 beforeBlur : function(){
37351 var v = this.parseDate(this.getRawValue());
37357 /** @cfg {Boolean} grow @hide */
37358 /** @cfg {Number} growMin @hide */
37359 /** @cfg {Number} growMax @hide */
37366 * Ext JS Library 1.1.1
37367 * Copyright(c) 2006-2007, Ext JS, LLC.
37369 * Originally Released Under LGPL - original licence link has changed is not relivant.
37372 * <script type="text/javascript">
37377 * @class Roo.form.ComboBox
37378 * @extends Roo.form.TriggerField
37379 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37381 * Create a new ComboBox.
37382 * @param {Object} config Configuration options
37384 Roo.form.ComboBox = function(config){
37385 Roo.form.ComboBox.superclass.constructor.call(this, config);
37389 * Fires when the dropdown list is expanded
37390 * @param {Roo.form.ComboBox} combo This combo box
37395 * Fires when the dropdown list is collapsed
37396 * @param {Roo.form.ComboBox} combo This combo box
37400 * @event beforeselect
37401 * Fires before a list item is selected. Return false to cancel the selection.
37402 * @param {Roo.form.ComboBox} combo This combo box
37403 * @param {Roo.data.Record} record The data record returned from the underlying store
37404 * @param {Number} index The index of the selected item in the dropdown list
37406 'beforeselect' : true,
37409 * Fires when a list item is selected
37410 * @param {Roo.form.ComboBox} combo This combo box
37411 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37412 * @param {Number} index The index of the selected item in the dropdown list
37416 * @event beforequery
37417 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37418 * The event object passed has these properties:
37419 * @param {Roo.form.ComboBox} combo This combo box
37420 * @param {String} query The query
37421 * @param {Boolean} forceAll true to force "all" query
37422 * @param {Boolean} cancel true to cancel the query
37423 * @param {Object} e The query event object
37425 'beforequery': true,
37428 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37429 * @param {Roo.form.ComboBox} combo This combo box
37434 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37435 * @param {Roo.form.ComboBox} combo This combo box
37436 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37442 if(this.transform){
37443 this.allowDomMove = false;
37444 var s = Roo.getDom(this.transform);
37445 if(!this.hiddenName){
37446 this.hiddenName = s.name;
37449 this.mode = 'local';
37450 var d = [], opts = s.options;
37451 for(var i = 0, len = opts.length;i < len; i++){
37453 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37455 this.value = value;
37457 d.push([value, o.text]);
37459 this.store = new Roo.data.SimpleStore({
37461 fields: ['value', 'text'],
37464 this.valueField = 'value';
37465 this.displayField = 'text';
37467 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37468 if(!this.lazyRender){
37469 this.target = true;
37470 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37471 s.parentNode.removeChild(s); // remove it
37472 this.render(this.el.parentNode);
37474 s.parentNode.removeChild(s); // remove it
37479 this.store = Roo.factory(this.store, Roo.data);
37482 this.selectedIndex = -1;
37483 if(this.mode == 'local'){
37484 if(config.queryDelay === undefined){
37485 this.queryDelay = 10;
37487 if(config.minChars === undefined){
37493 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37495 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37498 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37499 * rendering into an Roo.Editor, defaults to false)
37502 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37503 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37506 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37509 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37510 * the dropdown list (defaults to undefined, with no header element)
37514 * @cfg {String/Roo.Template} tpl The template to use to render the output
37518 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37520 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37522 listWidth: undefined,
37524 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37525 * mode = 'remote' or 'text' if mode = 'local')
37527 displayField: undefined,
37529 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37530 * mode = 'remote' or 'value' if mode = 'local').
37531 * Note: use of a valueField requires the user make a selection
37532 * in order for a value to be mapped.
37534 valueField: undefined,
37538 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37539 * field's data value (defaults to the underlying DOM element's name)
37541 hiddenName: undefined,
37543 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37547 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37549 selectedClass: 'x-combo-selected',
37551 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37552 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37553 * which displays a downward arrow icon).
37555 triggerClass : 'x-form-arrow-trigger',
37557 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37561 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37562 * anchor positions (defaults to 'tl-bl')
37564 listAlign: 'tl-bl?',
37566 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37570 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37571 * query specified by the allQuery config option (defaults to 'query')
37573 triggerAction: 'query',
37575 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37576 * (defaults to 4, does not apply if editable = false)
37580 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37581 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37585 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37586 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37590 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37591 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37595 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37596 * when editable = true (defaults to false)
37598 selectOnFocus:false,
37600 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37602 queryParam: 'query',
37604 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37605 * when mode = 'remote' (defaults to 'Loading...')
37607 loadingText: 'Loading...',
37609 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37613 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37617 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37618 * traditional select (defaults to true)
37622 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37626 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37630 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37631 * listWidth has a higher value)
37635 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37636 * allow the user to set arbitrary text into the field (defaults to false)
37638 forceSelection:false,
37640 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37641 * if typeAhead = true (defaults to 250)
37643 typeAheadDelay : 250,
37645 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37646 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37648 valueNotFoundText : undefined,
37650 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37652 blockFocus : false,
37655 * @cfg {Boolean} disableClear Disable showing of clear button.
37657 disableClear : false,
37659 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37661 alwaysQuery : false,
37667 // element that contains real text value.. (when hidden is used..)
37670 onRender : function(ct, position){
37671 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37672 if(this.hiddenName){
37673 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37675 this.hiddenField.value =
37676 this.hiddenValue !== undefined ? this.hiddenValue :
37677 this.value !== undefined ? this.value : '';
37679 // prevent input submission
37680 this.el.dom.removeAttribute('name');
37685 this.el.dom.setAttribute('autocomplete', 'off');
37688 var cls = 'x-combo-list';
37690 this.list = new Roo.Layer({
37691 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37694 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37695 this.list.setWidth(lw);
37696 this.list.swallowEvent('mousewheel');
37697 this.assetHeight = 0;
37700 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37701 this.assetHeight += this.header.getHeight();
37704 this.innerList = this.list.createChild({cls:cls+'-inner'});
37705 this.innerList.on('mouseover', this.onViewOver, this);
37706 this.innerList.on('mousemove', this.onViewMove, this);
37707 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37709 if(this.allowBlank && !this.pageSize && !this.disableClear){
37710 this.footer = this.list.createChild({cls:cls+'-ft'});
37711 this.pageTb = new Roo.Toolbar(this.footer);
37715 this.footer = this.list.createChild({cls:cls+'-ft'});
37716 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37717 {pageSize: this.pageSize});
37721 if (this.pageTb && this.allowBlank && !this.disableClear) {
37723 this.pageTb.add(new Roo.Toolbar.Fill(), {
37724 cls: 'x-btn-icon x-btn-clear',
37726 handler: function()
37729 _this.clearValue();
37730 _this.onSelect(false, -1);
37735 this.assetHeight += this.footer.getHeight();
37740 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37743 this.view = new Roo.View(this.innerList, this.tpl, {
37744 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37747 this.view.on('click', this.onViewClick, this);
37749 this.store.on('beforeload', this.onBeforeLoad, this);
37750 this.store.on('load', this.onLoad, this);
37751 this.store.on('loadexception', this.onLoadException, this);
37753 if(this.resizable){
37754 this.resizer = new Roo.Resizable(this.list, {
37755 pinned:true, handles:'se'
37757 this.resizer.on('resize', function(r, w, h){
37758 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37759 this.listWidth = w;
37760 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37761 this.restrictHeight();
37763 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37765 if(!this.editable){
37766 this.editable = true;
37767 this.setEditable(false);
37771 if (typeof(this.events.add.listeners) != 'undefined') {
37773 this.addicon = this.wrap.createChild(
37774 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37776 this.addicon.on('click', function(e) {
37777 this.fireEvent('add', this);
37780 if (typeof(this.events.edit.listeners) != 'undefined') {
37782 this.editicon = this.wrap.createChild(
37783 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37784 if (this.addicon) {
37785 this.editicon.setStyle('margin-left', '40px');
37787 this.editicon.on('click', function(e) {
37789 // we fire even if inothing is selected..
37790 this.fireEvent('edit', this, this.lastData );
37800 initEvents : function(){
37801 Roo.form.ComboBox.superclass.initEvents.call(this);
37803 this.keyNav = new Roo.KeyNav(this.el, {
37804 "up" : function(e){
37805 this.inKeyMode = true;
37809 "down" : function(e){
37810 if(!this.isExpanded()){
37811 this.onTriggerClick();
37813 this.inKeyMode = true;
37818 "enter" : function(e){
37819 this.onViewClick();
37823 "esc" : function(e){
37827 "tab" : function(e){
37828 this.onViewClick(false);
37829 this.fireEvent("specialkey", this, e);
37835 doRelay : function(foo, bar, hname){
37836 if(hname == 'down' || this.scope.isExpanded()){
37837 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37844 this.queryDelay = Math.max(this.queryDelay || 10,
37845 this.mode == 'local' ? 10 : 250);
37846 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37847 if(this.typeAhead){
37848 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37850 if(this.editable !== false){
37851 this.el.on("keyup", this.onKeyUp, this);
37853 if(this.forceSelection){
37854 this.on('blur', this.doForce, this);
37858 onDestroy : function(){
37860 this.view.setStore(null);
37861 this.view.el.removeAllListeners();
37862 this.view.el.remove();
37863 this.view.purgeListeners();
37866 this.list.destroy();
37869 this.store.un('beforeload', this.onBeforeLoad, this);
37870 this.store.un('load', this.onLoad, this);
37871 this.store.un('loadexception', this.onLoadException, this);
37873 Roo.form.ComboBox.superclass.onDestroy.call(this);
37877 fireKey : function(e){
37878 if(e.isNavKeyPress() && !this.list.isVisible()){
37879 this.fireEvent("specialkey", this, e);
37884 onResize: function(w, h){
37885 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37887 if(typeof w != 'number'){
37888 // we do not handle it!?!?
37891 var tw = this.trigger.getWidth();
37892 tw += this.addicon ? this.addicon.getWidth() : 0;
37893 tw += this.editicon ? this.editicon.getWidth() : 0;
37895 this.el.setWidth( this.adjustWidth('input', x));
37897 this.trigger.setStyle('left', x+'px');
37899 if(this.list && this.listWidth === undefined){
37900 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37901 this.list.setWidth(lw);
37902 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37910 * Allow or prevent the user from directly editing the field text. If false is passed,
37911 * the user will only be able to select from the items defined in the dropdown list. This method
37912 * is the runtime equivalent of setting the 'editable' config option at config time.
37913 * @param {Boolean} value True to allow the user to directly edit the field text
37915 setEditable : function(value){
37916 if(value == this.editable){
37919 this.editable = value;
37921 this.el.dom.setAttribute('readOnly', true);
37922 this.el.on('mousedown', this.onTriggerClick, this);
37923 this.el.addClass('x-combo-noedit');
37925 this.el.dom.setAttribute('readOnly', false);
37926 this.el.un('mousedown', this.onTriggerClick, this);
37927 this.el.removeClass('x-combo-noedit');
37932 onBeforeLoad : function(){
37933 if(!this.hasFocus){
37936 this.innerList.update(this.loadingText ?
37937 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37938 this.restrictHeight();
37939 this.selectedIndex = -1;
37943 onLoad : function(){
37944 if(!this.hasFocus){
37947 if(this.store.getCount() > 0){
37949 this.restrictHeight();
37950 if(this.lastQuery == this.allQuery){
37952 this.el.dom.select();
37954 if(!this.selectByValue(this.value, true)){
37955 this.select(0, true);
37959 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37960 this.taTask.delay(this.typeAheadDelay);
37964 this.onEmptyResults();
37969 onLoadException : function()
37972 Roo.log(this.store.reader.jsonData);
37973 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
37974 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
37980 onTypeAhead : function(){
37981 if(this.store.getCount() > 0){
37982 var r = this.store.getAt(0);
37983 var newValue = r.data[this.displayField];
37984 var len = newValue.length;
37985 var selStart = this.getRawValue().length;
37986 if(selStart != len){
37987 this.setRawValue(newValue);
37988 this.selectText(selStart, newValue.length);
37994 onSelect : function(record, index){
37995 if(this.fireEvent('beforeselect', this, record, index) !== false){
37996 this.setFromData(index > -1 ? record.data : false);
37998 this.fireEvent('select', this, record, index);
38003 * Returns the currently selected field value or empty string if no value is set.
38004 * @return {String} value The selected value
38006 getValue : function(){
38007 if(this.valueField){
38008 return typeof this.value != 'undefined' ? this.value : '';
38010 return Roo.form.ComboBox.superclass.getValue.call(this);
38015 * Clears any text/value currently set in the field
38017 clearValue : function(){
38018 if(this.hiddenField){
38019 this.hiddenField.value = '';
38022 this.setRawValue('');
38023 this.lastSelectionText = '';
38024 this.applyEmptyText();
38028 * Sets the specified value into the field. If the value finds a match, the corresponding record text
38029 * will be displayed in the field. If the value does not match the data value of an existing item,
38030 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
38031 * Otherwise the field will be blank (although the value will still be set).
38032 * @param {String} value The value to match
38034 setValue : function(v){
38036 if(this.valueField){
38037 var r = this.findRecord(this.valueField, v);
38039 text = r.data[this.displayField];
38040 }else if(this.valueNotFoundText !== undefined){
38041 text = this.valueNotFoundText;
38044 this.lastSelectionText = text;
38045 if(this.hiddenField){
38046 this.hiddenField.value = v;
38048 Roo.form.ComboBox.superclass.setValue.call(this, text);
38052 * @property {Object} the last set data for the element
38057 * Sets the value of the field based on a object which is related to the record format for the store.
38058 * @param {Object} value the value to set as. or false on reset?
38060 setFromData : function(o){
38061 var dv = ''; // display value
38062 var vv = ''; // value value..
38064 if (this.displayField) {
38065 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
38067 // this is an error condition!!!
38068 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
38071 if(this.valueField){
38072 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
38074 if(this.hiddenField){
38075 this.hiddenField.value = vv;
38077 this.lastSelectionText = dv;
38078 Roo.form.ComboBox.superclass.setValue.call(this, dv);
38082 // no hidden field.. - we store the value in 'value', but still display
38083 // display field!!!!
38084 this.lastSelectionText = dv;
38085 Roo.form.ComboBox.superclass.setValue.call(this, dv);
38091 reset : function(){
38092 // overridden so that last data is reset..
38093 this.setValue(this.originalValue);
38094 this.clearInvalid();
38095 this.lastData = false;
38098 findRecord : function(prop, value){
38100 if(this.store.getCount() > 0){
38101 this.store.each(function(r){
38102 if(r.data[prop] == value){
38112 getName: function()
38114 // returns hidden if it's set..
38115 if (!this.rendered) {return ''};
38116 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38120 onViewMove : function(e, t){
38121 this.inKeyMode = false;
38125 onViewOver : function(e, t){
38126 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38129 var item = this.view.findItemFromChild(t);
38131 var index = this.view.indexOf(item);
38132 this.select(index, false);
38137 onViewClick : function(doFocus)
38139 var index = this.view.getSelectedIndexes()[0];
38140 var r = this.store.getAt(index);
38142 this.onSelect(r, index);
38144 if(doFocus !== false && !this.blockFocus){
38150 restrictHeight : function(){
38151 this.innerList.dom.style.height = '';
38152 var inner = this.innerList.dom;
38153 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
38154 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
38155 this.list.beginUpdate();
38156 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
38157 this.list.alignTo(this.el, this.listAlign);
38158 this.list.endUpdate();
38162 onEmptyResults : function(){
38167 * Returns true if the dropdown list is expanded, else false.
38169 isExpanded : function(){
38170 return this.list.isVisible();
38174 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
38175 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38176 * @param {String} value The data value of the item to select
38177 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38178 * selected item if it is not currently in view (defaults to true)
38179 * @return {Boolean} True if the value matched an item in the list, else false
38181 selectByValue : function(v, scrollIntoView){
38182 if(v !== undefined && v !== null){
38183 var r = this.findRecord(this.valueField || this.displayField, v);
38185 this.select(this.store.indexOf(r), scrollIntoView);
38193 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
38194 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38195 * @param {Number} index The zero-based index of the list item to select
38196 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38197 * selected item if it is not currently in view (defaults to true)
38199 select : function(index, scrollIntoView){
38200 this.selectedIndex = index;
38201 this.view.select(index);
38202 if(scrollIntoView !== false){
38203 var el = this.view.getNode(index);
38205 this.innerList.scrollChildIntoView(el, false);
38211 selectNext : function(){
38212 var ct = this.store.getCount();
38214 if(this.selectedIndex == -1){
38216 }else if(this.selectedIndex < ct-1){
38217 this.select(this.selectedIndex+1);
38223 selectPrev : function(){
38224 var ct = this.store.getCount();
38226 if(this.selectedIndex == -1){
38228 }else if(this.selectedIndex != 0){
38229 this.select(this.selectedIndex-1);
38235 onKeyUp : function(e){
38236 if(this.editable !== false && !e.isSpecialKey()){
38237 this.lastKey = e.getKey();
38238 this.dqTask.delay(this.queryDelay);
38243 validateBlur : function(){
38244 return !this.list || !this.list.isVisible();
38248 initQuery : function(){
38249 this.doQuery(this.getRawValue());
38253 doForce : function(){
38254 if(this.el.dom.value.length > 0){
38255 this.el.dom.value =
38256 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
38257 this.applyEmptyText();
38262 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
38263 * query allowing the query action to be canceled if needed.
38264 * @param {String} query The SQL query to execute
38265 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38266 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
38267 * saved in the current store (defaults to false)
38269 doQuery : function(q, forceAll){
38270 if(q === undefined || q === null){
38275 forceAll: forceAll,
38279 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38283 forceAll = qe.forceAll;
38284 if(forceAll === true || (q.length >= this.minChars)){
38285 if(this.lastQuery != q || this.alwaysQuery){
38286 this.lastQuery = q;
38287 if(this.mode == 'local'){
38288 this.selectedIndex = -1;
38290 this.store.clearFilter();
38292 this.store.filter(this.displayField, q);
38296 this.store.baseParams[this.queryParam] = q;
38298 params: this.getParams(q)
38303 this.selectedIndex = -1;
38310 getParams : function(q){
38312 //p[this.queryParam] = q;
38315 p.limit = this.pageSize;
38321 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38323 collapse : function(){
38324 if(!this.isExpanded()){
38328 Roo.get(document).un('mousedown', this.collapseIf, this);
38329 Roo.get(document).un('mousewheel', this.collapseIf, this);
38330 if (!this.editable) {
38331 Roo.get(document).un('keydown', this.listKeyPress, this);
38333 this.fireEvent('collapse', this);
38337 collapseIf : function(e){
38338 if(!e.within(this.wrap) && !e.within(this.list)){
38344 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38346 expand : function(){
38347 if(this.isExpanded() || !this.hasFocus){
38350 this.list.alignTo(this.el, this.listAlign);
38352 Roo.get(document).on('mousedown', this.collapseIf, this);
38353 Roo.get(document).on('mousewheel', this.collapseIf, this);
38354 if (!this.editable) {
38355 Roo.get(document).on('keydown', this.listKeyPress, this);
38358 this.fireEvent('expand', this);
38362 // Implements the default empty TriggerField.onTriggerClick function
38363 onTriggerClick : function(){
38367 if(this.isExpanded()){
38369 if (!this.blockFocus) {
38374 this.hasFocus = true;
38375 if(this.triggerAction == 'all') {
38376 this.doQuery(this.allQuery, true);
38378 this.doQuery(this.getRawValue());
38380 if (!this.blockFocus) {
38385 listKeyPress : function(e)
38387 //Roo.log('listkeypress');
38388 // scroll to first matching element based on key pres..
38389 if (e.isSpecialKey()) {
38392 var k = String.fromCharCode(e.getKey()).toUpperCase();
38395 var csel = this.view.getSelectedNodes();
38396 var cselitem = false;
38398 var ix = this.view.indexOf(csel[0]);
38399 cselitem = this.store.getAt(ix);
38400 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38406 this.store.each(function(v) {
38408 // start at existing selection.
38409 if (cselitem.id == v.id) {
38415 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38416 match = this.store.indexOf(v);
38421 if (match === false) {
38422 return true; // no more action?
38425 this.view.select(match);
38426 var sn = Roo.get(this.view.getSelectedNodes()[0])
38427 sn.scrollIntoView(sn.dom.parentNode, false);
38431 * @cfg {Boolean} grow
38435 * @cfg {Number} growMin
38439 * @cfg {Number} growMax
38448 * Ext JS Library 1.1.1
38449 * Copyright(c) 2006-2007, Ext JS, LLC.
38451 * Originally Released Under LGPL - original licence link has changed is not relivant.
38454 * <script type="text/javascript">
38457 * @class Roo.form.Checkbox
38458 * @extends Roo.form.Field
38459 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38461 * Creates a new Checkbox
38462 * @param {Object} config Configuration options
38464 Roo.form.Checkbox = function(config){
38465 Roo.form.Checkbox.superclass.constructor.call(this, config);
38469 * Fires when the checkbox is checked or unchecked.
38470 * @param {Roo.form.Checkbox} this This checkbox
38471 * @param {Boolean} checked The new checked value
38477 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38479 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38481 focusClass : undefined,
38483 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38485 fieldClass: "x-form-field",
38487 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38491 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38492 * {tag: "input", type: "checkbox", autocomplete: "off"})
38494 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38496 * @cfg {String} boxLabel The text that appears beside the checkbox
38500 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38504 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38506 valueOff: '0', // value when not checked..
38508 actionMode : 'viewEl',
38511 itemCls : 'x-menu-check-item x-form-item',
38512 groupClass : 'x-menu-group-item',
38513 inputType : 'hidden',
38516 inSetChecked: false, // check that we are not calling self...
38518 inputElement: false, // real input element?
38519 basedOn: false, // ????
38521 isFormField: true, // not sure where this is needed!!!!
38523 onResize : function(){
38524 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38525 if(!this.boxLabel){
38526 this.el.alignTo(this.wrap, 'c-c');
38530 initEvents : function(){
38531 Roo.form.Checkbox.superclass.initEvents.call(this);
38532 this.el.on("click", this.onClick, this);
38533 this.el.on("change", this.onClick, this);
38537 getResizeEl : function(){
38541 getPositionEl : function(){
38546 onRender : function(ct, position){
38547 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38549 if(this.inputValue !== undefined){
38550 this.el.dom.value = this.inputValue;
38553 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38554 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38555 var viewEl = this.wrap.createChild({
38556 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38557 this.viewEl = viewEl;
38558 this.wrap.on('click', this.onClick, this);
38560 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38561 this.el.on('propertychange', this.setFromHidden, this); //ie
38566 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38567 // viewEl.on('click', this.onClick, this);
38569 //if(this.checked){
38570 this.setChecked(this.checked);
38572 //this.checked = this.el.dom;
38578 initValue : Roo.emptyFn,
38581 * Returns the checked state of the checkbox.
38582 * @return {Boolean} True if checked, else false
38584 getValue : function(){
38586 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38588 return this.valueOff;
38593 onClick : function(){
38594 this.setChecked(!this.checked);
38596 //if(this.el.dom.checked != this.checked){
38597 // this.setValue(this.el.dom.checked);
38602 * Sets the checked state of the checkbox.
38603 * On is always based on a string comparison between inputValue and the param.
38604 * @param {Boolean/String} value - the value to set
38605 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38607 setValue : function(v,suppressEvent){
38610 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38611 //if(this.el && this.el.dom){
38612 // this.el.dom.checked = this.checked;
38613 // this.el.dom.defaultChecked = this.checked;
38615 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38616 //this.fireEvent("check", this, this.checked);
38619 setChecked : function(state,suppressEvent)
38621 if (this.inSetChecked) {
38622 this.checked = state;
38628 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38630 this.checked = state;
38631 if(suppressEvent !== true){
38632 this.fireEvent('check', this, state);
38634 this.inSetChecked = true;
38635 this.el.dom.value = state ? this.inputValue : this.valueOff;
38636 this.inSetChecked = false;
38639 // handle setting of hidden value by some other method!!?!?
38640 setFromHidden: function()
38645 //console.log("SET FROM HIDDEN");
38646 //alert('setFrom hidden');
38647 this.setValue(this.el.dom.value);
38650 onDestroy : function()
38653 Roo.get(this.viewEl).remove();
38656 Roo.form.Checkbox.superclass.onDestroy.call(this);
38661 * Ext JS Library 1.1.1
38662 * Copyright(c) 2006-2007, Ext JS, LLC.
38664 * Originally Released Under LGPL - original licence link has changed is not relivant.
38667 * <script type="text/javascript">
38671 * @class Roo.form.Radio
38672 * @extends Roo.form.Checkbox
38673 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38674 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38676 * Creates a new Radio
38677 * @param {Object} config Configuration options
38679 Roo.form.Radio = function(){
38680 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38682 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38683 inputType: 'radio',
38686 * If this radio is part of a group, it will return the selected value
38689 getGroupValue : function(){
38690 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38692 });//<script type="text/javascript">
38695 * Ext JS Library 1.1.1
38696 * Copyright(c) 2006-2007, Ext JS, LLC.
38697 * licensing@extjs.com
38699 * http://www.extjs.com/license
38705 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38706 * - IE ? - no idea how much works there.
38714 * @class Ext.form.HtmlEditor
38715 * @extends Ext.form.Field
38716 * Provides a lightweight HTML Editor component.
38718 * This has been tested on Fireforx / Chrome.. IE may not be so great..
38720 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38721 * supported by this editor.</b><br/><br/>
38722 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38723 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38725 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38727 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38731 * @cfg {String} createLinkText The default text for the create link prompt
38733 createLinkText : 'Please enter the URL for the link:',
38735 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38737 defaultLinkValue : 'http:/'+'/',
38740 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
38745 * @cfg {Number} height (in pixels)
38749 * @cfg {Number} width (in pixels)
38754 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
38757 stylesheets: false,
38762 // private properties
38763 validationEvent : false,
38765 initialized : false,
38767 sourceEditMode : false,
38768 onFocus : Roo.emptyFn,
38770 hideMode:'offsets',
38772 defaultAutoCreate : { // modified by initCompnoent..
38774 style:"width:500px;height:300px;",
38775 autocomplete: "off"
38779 initComponent : function(){
38782 * @event initialize
38783 * Fires when the editor is fully initialized (including the iframe)
38784 * @param {HtmlEditor} this
38789 * Fires when the editor is first receives the focus. Any insertion must wait
38790 * until after this event.
38791 * @param {HtmlEditor} this
38795 * @event beforesync
38796 * Fires before the textarea is updated with content from the editor iframe. Return false
38797 * to cancel the sync.
38798 * @param {HtmlEditor} this
38799 * @param {String} html
38803 * @event beforepush
38804 * Fires before the iframe editor is updated with content from the textarea. Return false
38805 * to cancel the push.
38806 * @param {HtmlEditor} this
38807 * @param {String} html
38812 * Fires when the textarea is updated with content from the editor iframe.
38813 * @param {HtmlEditor} this
38814 * @param {String} html
38819 * Fires when the iframe editor is updated with content from the textarea.
38820 * @param {HtmlEditor} this
38821 * @param {String} html
38825 * @event editmodechange
38826 * Fires when the editor switches edit modes
38827 * @param {HtmlEditor} this
38828 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38830 editmodechange: true,
38832 * @event editorevent
38833 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38834 * @param {HtmlEditor} this
38838 this.defaultAutoCreate = {
38840 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
38841 autocomplete: "off"
38846 * Protected method that will not generally be called directly. It
38847 * is called when the editor creates its toolbar. Override this method if you need to
38848 * add custom toolbar buttons.
38849 * @param {HtmlEditor} editor
38851 createToolbar : function(editor){
38852 if (!editor.toolbars || !editor.toolbars.length) {
38853 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38856 for (var i =0 ; i < editor.toolbars.length;i++) {
38857 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38858 editor.toolbars[i].init(editor);
38865 * Protected method that will not generally be called directly. It
38866 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38867 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38869 getDocMarkup : function(){
38872 if (this.stylesheets === false) {
38874 Roo.get(document.head).select('style').each(function(node) {
38875 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38878 Roo.get(document.head).select('link').each(function(node) {
38879 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38882 } else if (!this.stylesheets.length) {
38884 st = '<style type="text/css">' +
38885 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38888 Roo.each(this.stylesheets, function(s) {
38889 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
38894 st += '<style type="text/css">' +
38895 'IMG { cursor: pointer } ' +
38899 return '<html><head>' + st +
38900 //<style type="text/css">' +
38901 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38903 ' </head><body></body></html>';
38907 onRender : function(ct, position)
38910 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38911 this.el.dom.style.border = '0 none';
38912 this.el.dom.setAttribute('tabIndex', -1);
38913 this.el.addClass('x-hidden');
38914 if(Roo.isIE){ // fix IE 1px bogus margin
38915 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38917 this.wrap = this.el.wrap({
38918 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38921 if (this.resizable) {
38922 this.resizeEl = new Roo.Resizable(this.wrap, {
38926 minHeight : this.height,
38927 height: this.height,
38928 handles : this.resizable,
38931 resize : function(r, w, h) {
38932 _t.onResize(w,h); // -something
38939 this.frameId = Roo.id();
38941 this.createToolbar(this);
38945 var iframe = this.wrap.createChild({
38948 name: this.frameId,
38949 frameBorder : 'no',
38950 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38954 // console.log(iframe);
38955 //this.wrap.dom.appendChild(iframe);
38957 this.iframe = iframe.dom;
38959 this.assignDocWin();
38961 this.doc.designMode = 'on';
38964 this.doc.write(this.getDocMarkup());
38968 var task = { // must defer to wait for browser to be ready
38970 //console.log("run task?" + this.doc.readyState);
38971 this.assignDocWin();
38972 if(this.doc.body || this.doc.readyState == 'complete'){
38974 this.doc.designMode="on";
38978 Roo.TaskMgr.stop(task);
38979 this.initEditor.defer(10, this);
38986 Roo.TaskMgr.start(task);
38989 this.setSize(this.wrap.getSize());
38991 if (this.resizeEl) {
38992 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
38993 // should trigger onReize..
38998 onResize : function(w, h)
39000 //Roo.log('resize: ' +w + ',' + h );
39001 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
39002 if(this.el && this.iframe){
39003 if(typeof w == 'number'){
39004 var aw = w - this.wrap.getFrameWidth('lr');
39005 this.el.setWidth(this.adjustWidth('textarea', aw));
39006 this.iframe.style.width = aw + 'px';
39008 if(typeof h == 'number'){
39010 for (var i =0; i < this.toolbars.length;i++) {
39011 // fixme - ask toolbars for heights?
39012 tbh += this.toolbars[i].tb.el.getHeight();
39013 if (this.toolbars[i].footer) {
39014 tbh += this.toolbars[i].footer.el.getHeight();
39021 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
39022 ah -= 5; // knock a few pixes off for look..
39023 this.el.setHeight(this.adjustWidth('textarea', ah));
39024 this.iframe.style.height = ah + 'px';
39026 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
39033 * Toggles the editor between standard and source edit mode.
39034 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
39036 toggleSourceEdit : function(sourceEditMode){
39038 this.sourceEditMode = sourceEditMode === true;
39040 if(this.sourceEditMode){
39043 this.iframe.className = 'x-hidden';
39044 this.el.removeClass('x-hidden');
39045 this.el.dom.removeAttribute('tabIndex');
39050 this.iframe.className = '';
39051 this.el.addClass('x-hidden');
39052 this.el.dom.setAttribute('tabIndex', -1);
39055 this.setSize(this.wrap.getSize());
39056 this.fireEvent('editmodechange', this, this.sourceEditMode);
39059 // private used internally
39060 createLink : function(){
39061 var url = prompt(this.createLinkText, this.defaultLinkValue);
39062 if(url && url != 'http:/'+'/'){
39063 this.relayCmd('createlink', url);
39067 // private (for BoxComponent)
39068 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39070 // private (for BoxComponent)
39071 getResizeEl : function(){
39075 // private (for BoxComponent)
39076 getPositionEl : function(){
39081 initEvents : function(){
39082 this.originalValue = this.getValue();
39086 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
39089 markInvalid : Roo.emptyFn,
39091 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
39094 clearInvalid : Roo.emptyFn,
39096 setValue : function(v){
39097 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
39102 * Protected method that will not generally be called directly. If you need/want
39103 * custom HTML cleanup, this is the method you should override.
39104 * @param {String} html The HTML to be cleaned
39105 * return {String} The cleaned HTML
39107 cleanHtml : function(html){
39108 html = String(html);
39109 if(html.length > 5){
39110 if(Roo.isSafari){ // strip safari nonsense
39111 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
39114 if(html == ' '){
39121 * Protected method that will not generally be called directly. Syncs the contents
39122 * of the editor iframe with the textarea.
39124 syncValue : function(){
39125 if(this.initialized){
39126 var bd = (this.doc.body || this.doc.documentElement);
39127 //this.cleanUpPaste(); -- this is done else where and causes havoc..
39128 var html = bd.innerHTML;
39130 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
39131 var m = bs.match(/text-align:(.*?);/i);
39133 html = '<div style="'+m[0]+'">' + html + '</div>';
39136 html = this.cleanHtml(html);
39137 // fix up the special chars..
39138 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
39139 return "&#"+b.charCodeAt()+";"
39141 if(this.fireEvent('beforesync', this, html) !== false){
39142 this.el.dom.value = html;
39143 this.fireEvent('sync', this, html);
39149 * Protected method that will not generally be called directly. Pushes the value of the textarea
39150 * into the iframe editor.
39152 pushValue : function(){
39153 if(this.initialized){
39154 var v = this.el.dom.value;
39159 if(this.fireEvent('beforepush', this, v) !== false){
39160 var d = (this.doc.body || this.doc.documentElement);
39162 this.cleanUpPaste();
39163 this.el.dom.value = d.innerHTML;
39164 this.fireEvent('push', this, v);
39170 deferFocus : function(){
39171 this.focus.defer(10, this);
39175 focus : function(){
39176 if(this.win && !this.sourceEditMode){
39183 assignDocWin: function()
39185 var iframe = this.iframe;
39188 this.doc = iframe.contentWindow.document;
39189 this.win = iframe.contentWindow;
39191 if (!Roo.get(this.frameId)) {
39194 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
39195 this.win = Roo.get(this.frameId).dom.contentWindow;
39200 initEditor : function(){
39201 //console.log("INIT EDITOR");
39202 this.assignDocWin();
39206 this.doc.designMode="on";
39208 this.doc.write(this.getDocMarkup());
39211 var dbody = (this.doc.body || this.doc.documentElement);
39212 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
39213 // this copies styles from the containing element into thsi one..
39214 // not sure why we need all of this..
39215 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
39216 ss['background-attachment'] = 'fixed'; // w3c
39217 dbody.bgProperties = 'fixed'; // ie
39218 Roo.DomHelper.applyStyles(dbody, ss);
39219 Roo.EventManager.on(this.doc, {
39220 //'mousedown': this.onEditorEvent,
39221 'mouseup': this.onEditorEvent,
39222 'dblclick': this.onEditorEvent,
39223 'click': this.onEditorEvent,
39224 'keyup': this.onEditorEvent,
39229 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
39231 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
39232 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
39234 this.initialized = true;
39236 this.fireEvent('initialize', this);
39241 onDestroy : function(){
39247 for (var i =0; i < this.toolbars.length;i++) {
39248 // fixme - ask toolbars for heights?
39249 this.toolbars[i].onDestroy();
39252 this.wrap.dom.innerHTML = '';
39253 this.wrap.remove();
39258 onFirstFocus : function(){
39260 this.assignDocWin();
39263 this.activated = true;
39264 for (var i =0; i < this.toolbars.length;i++) {
39265 this.toolbars[i].onFirstFocus();
39268 if(Roo.isGecko){ // prevent silly gecko errors
39270 var s = this.win.getSelection();
39271 if(!s.focusNode || s.focusNode.nodeType != 3){
39272 var r = s.getRangeAt(0);
39273 r.selectNodeContents((this.doc.body || this.doc.documentElement));
39278 this.execCmd('useCSS', true);
39279 this.execCmd('styleWithCSS', false);
39282 this.fireEvent('activate', this);
39286 adjustFont: function(btn){
39287 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
39288 //if(Roo.isSafari){ // safari
39291 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
39292 if(Roo.isSafari){ // safari
39293 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
39294 v = (v < 10) ? 10 : v;
39295 v = (v > 48) ? 48 : v;
39296 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
39301 v = Math.max(1, v+adjust);
39303 this.execCmd('FontSize', v );
39306 onEditorEvent : function(e){
39307 this.fireEvent('editorevent', this, e);
39308 // this.updateToolbar();
39309 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
39312 insertTag : function(tg)
39314 // could be a bit smarter... -> wrap the current selected tRoo..
39316 this.execCmd("formatblock", tg);
39320 insertText : function(txt)
39324 range = this.createRange();
39325 range.deleteContents();
39326 //alert(Sender.getAttribute('label'));
39328 range.insertNode(this.doc.createTextNode(txt));
39332 relayBtnCmd : function(btn){
39333 this.relayCmd(btn.cmd);
39337 * Executes a Midas editor command on the editor document and performs necessary focus and
39338 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
39339 * @param {String} cmd The Midas command
39340 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39342 relayCmd : function(cmd, value){
39344 this.execCmd(cmd, value);
39345 this.fireEvent('editorevent', this);
39346 //this.updateToolbar();
39351 * Executes a Midas editor command directly on the editor document.
39352 * For visual commands, you should use {@link #relayCmd} instead.
39353 * <b>This should only be called after the editor is initialized.</b>
39354 * @param {String} cmd The Midas command
39355 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39357 execCmd : function(cmd, value){
39358 this.doc.execCommand(cmd, false, value === undefined ? null : value);
39365 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
39367 * @param {String} text | dom node..
39369 insertAtCursor : function(text)
39374 if(!this.activated){
39380 var r = this.doc.selection.createRange();
39391 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
39395 // from jquery ui (MIT licenced)
39397 var win = this.win;
39399 if (win.getSelection && win.getSelection().getRangeAt) {
39400 range = win.getSelection().getRangeAt(0);
39401 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
39402 range.insertNode(node);
39403 } else if (win.document.selection && win.document.selection.createRange) {
39404 // no firefox support
39405 var txt = typeof(text) == 'string' ? text : text.outerHTML;
39406 win.document.selection.createRange().pasteHTML(txt);
39408 // no firefox support
39409 var txt = typeof(text) == 'string' ? text : text.outerHTML;
39410 this.execCmd('InsertHTML', txt);
39419 mozKeyPress : function(e){
39421 var c = e.getCharCode(), cmd;
39424 c = String.fromCharCode(c).toLowerCase();
39438 this.cleanUpPaste.defer(100, this);
39446 e.preventDefault();
39454 fixKeys : function(){ // load time branching for fastest keydown performance
39456 return function(e){
39457 var k = e.getKey(), r;
39460 r = this.doc.selection.createRange();
39463 r.pasteHTML('    ');
39470 r = this.doc.selection.createRange();
39472 var target = r.parentElement();
39473 if(!target || target.tagName.toLowerCase() != 'li'){
39475 r.pasteHTML('<br />');
39481 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39482 this.cleanUpPaste.defer(100, this);
39488 }else if(Roo.isOpera){
39489 return function(e){
39490 var k = e.getKey();
39494 this.execCmd('InsertHTML','    ');
39497 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39498 this.cleanUpPaste.defer(100, this);
39503 }else if(Roo.isSafari){
39504 return function(e){
39505 var k = e.getKey();
39509 this.execCmd('InsertText','\t');
39513 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39514 this.cleanUpPaste.defer(100, this);
39522 getAllAncestors: function()
39524 var p = this.getSelectedNode();
39527 a.push(p); // push blank onto stack..
39528 p = this.getParentElement();
39532 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39536 a.push(this.doc.body);
39540 lastSelNode : false,
39543 getSelection : function()
39545 this.assignDocWin();
39546 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39549 getSelectedNode: function()
39551 // this may only work on Gecko!!!
39553 // should we cache this!!!!
39558 var range = this.createRange(this.getSelection()).cloneRange();
39561 var parent = range.parentElement();
39563 var testRange = range.duplicate();
39564 testRange.moveToElementText(parent);
39565 if (testRange.inRange(range)) {
39568 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39571 parent = parent.parentElement;
39576 // is ancestor a text element.
39577 var ac = range.commonAncestorContainer;
39578 if (ac.nodeType == 3) {
39579 ac = ac.parentNode;
39582 var ar = ac.childNodes;
39585 var other_nodes = [];
39586 var has_other_nodes = false;
39587 for (var i=0;i<ar.length;i++) {
39588 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39591 // fullly contained node.
39593 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39598 // probably selected..
39599 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39600 other_nodes.push(ar[i]);
39604 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39609 has_other_nodes = true;
39611 if (!nodes.length && other_nodes.length) {
39612 nodes= other_nodes;
39614 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39620 createRange: function(sel)
39622 // this has strange effects when using with
39623 // top toolbar - not sure if it's a great idea.
39624 //this.editor.contentWindow.focus();
39625 if (typeof sel != "undefined") {
39627 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39629 return this.doc.createRange();
39632 return this.doc.createRange();
39635 getParentElement: function()
39638 this.assignDocWin();
39639 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39641 var range = this.createRange(sel);
39644 var p = range.commonAncestorContainer;
39645 while (p.nodeType == 3) { // text node
39656 * Range intersection.. the hard stuff...
39660 * [ -- selected range --- ]
39664 * if end is before start or hits it. fail.
39665 * if start is after end or hits it fail.
39667 * if either hits (but other is outside. - then it's not
39673 // @see http://www.thismuchiknow.co.uk/?p=64.
39674 rangeIntersectsNode : function(range, node)
39676 var nodeRange = node.ownerDocument.createRange();
39678 nodeRange.selectNode(node);
39680 nodeRange.selectNodeContents(node);
39683 var rangeStartRange = range.cloneRange();
39684 rangeStartRange.collapse(true);
39686 var rangeEndRange = range.cloneRange();
39687 rangeEndRange.collapse(false);
39689 var nodeStartRange = nodeRange.cloneRange();
39690 nodeStartRange.collapse(true);
39692 var nodeEndRange = nodeRange.cloneRange();
39693 nodeEndRange.collapse(false);
39695 return rangeStartRange.compareBoundaryPoints(
39696 Range.START_TO_START, nodeEndRange) == -1 &&
39697 rangeEndRange.compareBoundaryPoints(
39698 Range.START_TO_START, nodeStartRange) == 1;
39702 rangeCompareNode : function(range, node)
39704 var nodeRange = node.ownerDocument.createRange();
39706 nodeRange.selectNode(node);
39708 nodeRange.selectNodeContents(node);
39712 range.collapse(true);
39714 nodeRange.collapse(true);
39716 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
39717 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
39719 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
39721 var nodeIsBefore = ss == 1;
39722 var nodeIsAfter = ee == -1;
39724 if (nodeIsBefore && nodeIsAfter)
39726 if (!nodeIsBefore && nodeIsAfter)
39727 return 1; //right trailed.
39729 if (nodeIsBefore && !nodeIsAfter)
39730 return 2; // left trailed.
39735 // private? - in a new class?
39736 cleanUpPaste : function()
39738 // cleans up the whole document..
39739 Roo.log('cleanuppaste');
39740 this.cleanUpChildren(this.doc.body);
39741 var clean = this.cleanWordChars(this.doc.body.innerHTML);
39742 if (clean != this.doc.body.innerHTML) {
39743 this.doc.body.innerHTML = clean;
39748 cleanWordChars : function(input) {
39749 var he = Roo.form.HtmlEditor;
39751 var output = input;
39752 Roo.each(he.swapCodes, function(sw) {
39754 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
39755 output = output.replace(swapper, sw[1]);
39761 cleanUpChildren : function (n)
39763 if (!n.childNodes.length) {
39766 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39767 this.cleanUpChild(n.childNodes[i]);
39774 cleanUpChild : function (node)
39776 //console.log(node);
39777 if (node.nodeName == "#text") {
39778 // clean up silly Windows -- stuff?
39781 if (node.nodeName == "#comment") {
39782 node.parentNode.removeChild(node);
39783 // clean up silly Windows -- stuff?
39787 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39789 node.parentNode.removeChild(node);
39794 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
39796 // remove <a name=....> as rendering on yahoo mailer is bored with this.
39798 if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
39799 remove_keep_children = true;
39802 if (remove_keep_children) {
39803 this.cleanUpChildren(node);
39804 // inserts everything just before this node...
39805 while (node.childNodes.length) {
39806 var cn = node.childNodes[0];
39807 node.removeChild(cn);
39808 node.parentNode.insertBefore(cn, node);
39810 node.parentNode.removeChild(node);
39814 if (!node.attributes || !node.attributes.length) {
39815 this.cleanUpChildren(node);
39819 function cleanAttr(n,v)
39822 if (v.match(/^\./) || v.match(/^\//)) {
39825 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39828 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39829 node.removeAttribute(n);
39833 function cleanStyle(n,v)
39835 if (v.match(/expression/)) { //XSS?? should we even bother..
39836 node.removeAttribute(n);
39841 var parts = v.split(/;/);
39842 Roo.each(parts, function(p) {
39843 p = p.replace(/\s+/g,'');
39847 var l = p.split(':').shift().replace(/\s+/g,'');
39849 // only allow 'c whitelisted system attributes'
39850 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39851 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39852 node.removeAttribute(n);
39862 for (var i = node.attributes.length-1; i > -1 ; i--) {
39863 var a = node.attributes[i];
39865 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39866 node.removeAttribute(a.name);
39869 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39870 cleanAttr(a.name,a.value); // fixme..
39873 if (a.name == 'style') {
39874 cleanStyle(a.name,a.value);
39876 /// clean up MS crap..
39877 // tecnically this should be a list of valid class'es..
39880 if (a.name == 'class') {
39881 if (a.value.match(/^Mso/)) {
39882 node.className = '';
39885 if (a.value.match(/body/)) {
39886 node.className = '';
39896 this.cleanUpChildren(node);
39902 // hide stuff that is not compatible
39916 * @event specialkey
39920 * @cfg {String} fieldClass @hide
39923 * @cfg {String} focusClass @hide
39926 * @cfg {String} autoCreate @hide
39929 * @cfg {String} inputType @hide
39932 * @cfg {String} invalidClass @hide
39935 * @cfg {String} invalidText @hide
39938 * @cfg {String} msgFx @hide
39941 * @cfg {String} validateOnBlur @hide
39945 Roo.form.HtmlEditor.white = [
39946 'area', 'br', 'img', 'input', 'hr', 'wbr',
39948 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39949 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39950 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39951 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39952 'table', 'ul', 'xmp',
39954 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39957 'dir', 'menu', 'ol', 'ul', 'dl',
39963 Roo.form.HtmlEditor.black = [
39964 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39966 'base', 'basefont', 'bgsound', 'blink', 'body',
39967 'frame', 'frameset', 'head', 'html', 'ilayer',
39968 'iframe', 'layer', 'link', 'meta', 'object',
39969 'script', 'style' ,'title', 'xml' // clean later..
39971 Roo.form.HtmlEditor.clean = [
39972 'script', 'style', 'title', 'xml'
39974 Roo.form.HtmlEditor.remove = [
39979 Roo.form.HtmlEditor.ablack = [
39983 Roo.form.HtmlEditor.aclean = [
39984 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39988 Roo.form.HtmlEditor.pwhite= [
39989 'http', 'https', 'mailto'
39992 // white listed style attributes.
39993 Roo.form.HtmlEditor.cwhite= [
39999 Roo.form.HtmlEditor.swapCodes =[
40010 // <script type="text/javascript">
40013 * Ext JS Library 1.1.1
40014 * Copyright(c) 2006-2007, Ext JS, LLC.
40020 * @class Roo.form.HtmlEditorToolbar1
40025 new Roo.form.HtmlEditor({
40028 new Roo.form.HtmlEditorToolbar1({
40029 disable : { fonts: 1 , format: 1, ..., ... , ...],
40035 * @cfg {Object} disable List of elements to disable..
40036 * @cfg {Array} btns List of additional buttons.
40040 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
40043 Roo.form.HtmlEditor.ToolbarStandard = function(config)
40046 Roo.apply(this, config);
40048 // default disabled, based on 'good practice'..
40049 this.disable = this.disable || {};
40050 Roo.applyIf(this.disable, {
40053 specialElements : true
40057 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40058 // dont call parent... till later.
40061 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
40069 * @cfg {Object} disable List of toolbar elements to disable
40074 * @cfg {Array} fontFamilies An array of available font families
40092 // "á" , ?? a acute?
40097 "°" // , // degrees
40099 // "é" , // e ecute
40100 // "ú" , // u ecute?
40103 specialElements : [
40105 text: "Insert Table",
40108 ihtml : '<table><tr><td>Cell</td></tr></table>'
40112 text: "Insert Image",
40115 ihtml : '<img src="about:blank"/>'
40124 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
40125 "input:submit", "input:button", "select", "textarea", "label" ],
40128 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
40130 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
40133 * @cfg {String} defaultFont default font to use.
40135 defaultFont: 'tahoma',
40137 fontSelect : false,
40140 formatCombo : false,
40142 init : function(editor)
40144 this.editor = editor;
40147 var fid = editor.frameId;
40149 function btn(id, toggle, handler){
40150 var xid = fid + '-'+ id ;
40154 cls : 'x-btn-icon x-edit-'+id,
40155 enableToggle:toggle !== false,
40156 scope: editor, // was editor...
40157 handler:handler||editor.relayBtnCmd,
40158 clickEvent:'mousedown',
40159 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40166 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
40168 // stop form submits
40169 tb.el.on('click', function(e){
40170 e.preventDefault(); // what does this do?
40173 if(!this.disable.font && !Roo.isSafari){
40174 /* why no safari for fonts
40175 editor.fontSelect = tb.el.createChild({
40178 cls:'x-font-select',
40179 html: editor.createFontOptions()
40181 editor.fontSelect.on('change', function(){
40182 var font = editor.fontSelect.dom.value;
40183 editor.relayCmd('fontname', font);
40184 editor.deferFocus();
40187 editor.fontSelect.dom,
40192 if(!this.disable.formats){
40193 this.formatCombo = new Roo.form.ComboBox({
40194 store: new Roo.data.SimpleStore({
40197 data : this.formats // from states.js
40200 //autoCreate : {tag: "div", size: "20"},
40201 displayField:'tag',
40205 triggerAction: 'all',
40206 emptyText:'Add tag',
40207 selectOnFocus:true,
40210 'select': function(c, r, i) {
40211 editor.insertTag(r.get('tag'));
40217 tb.addField(this.formatCombo);
40221 if(!this.disable.format){
40228 if(!this.disable.fontSize){
40233 btn('increasefontsize', false, editor.adjustFont),
40234 btn('decreasefontsize', false, editor.adjustFont)
40239 if(!this.disable.colors){
40242 id:editor.frameId +'-forecolor',
40243 cls:'x-btn-icon x-edit-forecolor',
40244 clickEvent:'mousedown',
40245 tooltip: this.buttonTips['forecolor'] || undefined,
40247 menu : new Roo.menu.ColorMenu({
40248 allowReselect: true,
40249 focus: Roo.emptyFn,
40252 selectHandler: function(cp, color){
40253 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
40254 editor.deferFocus();
40257 clickEvent:'mousedown'
40260 id:editor.frameId +'backcolor',
40261 cls:'x-btn-icon x-edit-backcolor',
40262 clickEvent:'mousedown',
40263 tooltip: this.buttonTips['backcolor'] || undefined,
40265 menu : new Roo.menu.ColorMenu({
40266 focus: Roo.emptyFn,
40269 allowReselect: true,
40270 selectHandler: function(cp, color){
40272 editor.execCmd('useCSS', false);
40273 editor.execCmd('hilitecolor', color);
40274 editor.execCmd('useCSS', true);
40275 editor.deferFocus();
40277 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
40278 Roo.isSafari || Roo.isIE ? '#'+color : color);
40279 editor.deferFocus();
40283 clickEvent:'mousedown'
40288 // now add all the items...
40291 if(!this.disable.alignments){
40294 btn('justifyleft'),
40295 btn('justifycenter'),
40296 btn('justifyright')
40300 //if(!Roo.isSafari){
40301 if(!this.disable.links){
40304 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
40308 if(!this.disable.lists){
40311 btn('insertorderedlist'),
40312 btn('insertunorderedlist')
40315 if(!this.disable.sourceEdit){
40318 btn('sourceedit', true, function(btn){
40319 this.toggleSourceEdit(btn.pressed);
40326 // special menu.. - needs to be tidied up..
40327 if (!this.disable.special) {
40330 cls: 'x-edit-none',
40336 for (var i =0; i < this.specialChars.length; i++) {
40337 smenu.menu.items.push({
40339 html: this.specialChars[i],
40340 handler: function(a,b) {
40341 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
40342 //editor.insertAtCursor(a.html);
40355 if (!this.disable.specialElements) {
40358 cls: 'x-edit-none',
40363 for (var i =0; i < this.specialElements.length; i++) {
40364 semenu.menu.items.push(
40366 handler: function(a,b) {
40367 editor.insertAtCursor(this.ihtml);
40369 }, this.specialElements[i])
40381 for(var i =0; i< this.btns.length;i++) {
40382 var b = this.btns[i];
40383 b.cls = 'x-edit-none';
40392 // disable everything...
40394 this.tb.items.each(function(item){
40395 if(item.id != editor.frameId+ '-sourceedit'){
40399 this.rendered = true;
40401 // the all the btns;
40402 editor.on('editorevent', this.updateToolbar, this);
40403 // other toolbars need to implement this..
40404 //editor.on('editmodechange', this.updateToolbar, this);
40410 * Protected method that will not generally be called directly. It triggers
40411 * a toolbar update by reading the markup state of the current selection in the editor.
40413 updateToolbar: function(){
40415 if(!this.editor.activated){
40416 this.editor.onFirstFocus();
40420 var btns = this.tb.items.map,
40421 doc = this.editor.doc,
40422 frameId = this.editor.frameId;
40424 if(!this.disable.font && !Roo.isSafari){
40426 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
40427 if(name != this.fontSelect.dom.value){
40428 this.fontSelect.dom.value = name;
40432 if(!this.disable.format){
40433 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
40434 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
40435 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
40437 if(!this.disable.alignments){
40438 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
40439 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
40440 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
40442 if(!Roo.isSafari && !this.disable.lists){
40443 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
40444 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
40447 var ans = this.editor.getAllAncestors();
40448 if (this.formatCombo) {
40451 var store = this.formatCombo.store;
40452 this.formatCombo.setValue("");
40453 for (var i =0; i < ans.length;i++) {
40454 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
40456 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
40464 // hides menus... - so this cant be on a menu...
40465 Roo.menu.MenuMgr.hideAll();
40467 //this.editorsyncValue();
40471 createFontOptions : function(){
40472 var buf = [], fs = this.fontFamilies, ff, lc;
40473 for(var i = 0, len = fs.length; i< len; i++){
40475 lc = ff.toLowerCase();
40477 '<option value="',lc,'" style="font-family:',ff,';"',
40478 (this.defaultFont == lc ? ' selected="true">' : '>'),
40483 return buf.join('');
40486 toggleSourceEdit : function(sourceEditMode){
40487 if(sourceEditMode === undefined){
40488 sourceEditMode = !this.sourceEditMode;
40490 this.sourceEditMode = sourceEditMode === true;
40491 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
40492 // just toggle the button?
40493 if(btn.pressed !== this.editor.sourceEditMode){
40494 btn.toggle(this.editor.sourceEditMode);
40498 if(this.sourceEditMode){
40499 this.tb.items.each(function(item){
40500 if(item.cmd != 'sourceedit'){
40506 if(this.initialized){
40507 this.tb.items.each(function(item){
40513 // tell the editor that it's been pressed..
40514 this.editor.toggleSourceEdit(sourceEditMode);
40518 * Object collection of toolbar tooltips for the buttons in the editor. The key
40519 * is the command id associated with that button and the value is a valid QuickTips object.
40524 title: 'Bold (Ctrl+B)',
40525 text: 'Make the selected text bold.',
40526 cls: 'x-html-editor-tip'
40529 title: 'Italic (Ctrl+I)',
40530 text: 'Make the selected text italic.',
40531 cls: 'x-html-editor-tip'
40539 title: 'Bold (Ctrl+B)',
40540 text: 'Make the selected text bold.',
40541 cls: 'x-html-editor-tip'
40544 title: 'Italic (Ctrl+I)',
40545 text: 'Make the selected text italic.',
40546 cls: 'x-html-editor-tip'
40549 title: 'Underline (Ctrl+U)',
40550 text: 'Underline the selected text.',
40551 cls: 'x-html-editor-tip'
40553 increasefontsize : {
40554 title: 'Grow Text',
40555 text: 'Increase the font size.',
40556 cls: 'x-html-editor-tip'
40558 decreasefontsize : {
40559 title: 'Shrink Text',
40560 text: 'Decrease the font size.',
40561 cls: 'x-html-editor-tip'
40564 title: 'Text Highlight Color',
40565 text: 'Change the background color of the selected text.',
40566 cls: 'x-html-editor-tip'
40569 title: 'Font Color',
40570 text: 'Change the color of the selected text.',
40571 cls: 'x-html-editor-tip'
40574 title: 'Align Text Left',
40575 text: 'Align text to the left.',
40576 cls: 'x-html-editor-tip'
40579 title: 'Center Text',
40580 text: 'Center text in the editor.',
40581 cls: 'x-html-editor-tip'
40584 title: 'Align Text Right',
40585 text: 'Align text to the right.',
40586 cls: 'x-html-editor-tip'
40588 insertunorderedlist : {
40589 title: 'Bullet List',
40590 text: 'Start a bulleted list.',
40591 cls: 'x-html-editor-tip'
40593 insertorderedlist : {
40594 title: 'Numbered List',
40595 text: 'Start a numbered list.',
40596 cls: 'x-html-editor-tip'
40599 title: 'Hyperlink',
40600 text: 'Make the selected text a hyperlink.',
40601 cls: 'x-html-editor-tip'
40604 title: 'Source Edit',
40605 text: 'Switch to source editing mode.',
40606 cls: 'x-html-editor-tip'
40610 onDestroy : function(){
40613 this.tb.items.each(function(item){
40615 item.menu.removeAll();
40617 item.menu.el.destroy();
40625 onFirstFocus: function() {
40626 this.tb.items.each(function(item){
40635 // <script type="text/javascript">
40638 * Ext JS Library 1.1.1
40639 * Copyright(c) 2006-2007, Ext JS, LLC.
40646 * @class Roo.form.HtmlEditor.ToolbarContext
40651 new Roo.form.HtmlEditor({
40654 { xtype: 'ToolbarStandard', styles : {} }
40655 { xtype: 'ToolbarContext', disable : {} }
40661 * @config : {Object} disable List of elements to disable.. (not done yet.)
40662 * @config : {Object} styles Map of styles available.
40666 Roo.form.HtmlEditor.ToolbarContext = function(config)
40669 Roo.apply(this, config);
40670 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40671 // dont call parent... till later.
40672 this.styles = this.styles || {};
40674 Roo.form.HtmlEditor.ToolbarContext.types = {
40686 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40748 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40753 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40807 // should we really allow this??
40808 // should this just be
40823 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40831 * @cfg {Object} disable List of toolbar elements to disable
40836 * @cfg {Object} styles List of styles
40837 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
40839 * These must be defined in the page, so they get rendered correctly..
40850 init : function(editor)
40852 this.editor = editor;
40855 var fid = editor.frameId;
40857 function btn(id, toggle, handler){
40858 var xid = fid + '-'+ id ;
40862 cls : 'x-btn-icon x-edit-'+id,
40863 enableToggle:toggle !== false,
40864 scope: editor, // was editor...
40865 handler:handler||editor.relayBtnCmd,
40866 clickEvent:'mousedown',
40867 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40871 // create a new element.
40872 var wdiv = editor.wrap.createChild({
40874 }, editor.wrap.dom.firstChild.nextSibling, true);
40876 // can we do this more than once??
40878 // stop form submits
40881 // disable everything...
40882 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40883 this.toolbars = {};
40885 for (var i in ty) {
40887 this.toolbars[i] = this.buildToolbar(ty[i],i);
40889 this.tb = this.toolbars.BODY;
40891 this.buildFooter();
40892 this.footer.show();
40894 this.rendered = true;
40896 // the all the btns;
40897 editor.on('editorevent', this.updateToolbar, this);
40898 // other toolbars need to implement this..
40899 //editor.on('editmodechange', this.updateToolbar, this);
40905 * Protected method that will not generally be called directly. It triggers
40906 * a toolbar update by reading the markup state of the current selection in the editor.
40908 updateToolbar: function(editor,ev,sel){
40911 // capture mouse up - this is handy for selecting images..
40912 // perhaps should go somewhere else...
40913 if(!this.editor.activated){
40914 this.editor.onFirstFocus();
40918 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
40919 // selectNode - might want to handle IE?
40921 (ev.type == 'mouseup' || ev.type == 'click' ) &&
40922 ev.target && ev.target.tagName == 'IMG') {
40923 // they have click on an image...
40924 // let's see if we can change the selection...
40927 var nodeRange = sel.ownerDocument.createRange();
40929 nodeRange.selectNode(sel);
40931 nodeRange.selectNodeContents(sel);
40933 //nodeRange.collapse(true);
40934 var s = editor.win.getSelection();
40935 s.removeAllRanges();
40936 s.addRange(nodeRange);
40940 var updateFooter = sel ? false : true;
40943 var ans = this.editor.getAllAncestors();
40946 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40949 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40950 sel = sel ? sel : this.editor.doc.body;
40951 sel = sel.tagName.length ? sel : this.editor.doc.body;
40954 // pick a menu that exists..
40955 var tn = sel.tagName.toUpperCase();
40956 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40958 tn = sel.tagName.toUpperCase();
40960 var lastSel = this.tb.selectedNode
40962 this.tb.selectedNode = sel;
40964 // if current menu does not match..
40965 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
40968 ///console.log("show: " + tn);
40969 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
40972 this.tb.items.first().el.innerHTML = tn + ': ';
40975 // update attributes
40976 if (this.tb.fields) {
40977 this.tb.fields.each(function(e) {
40978 e.setValue(sel.getAttribute(e.name));
40982 var hasStyles = false;
40983 for(var i in this.styles) {
40990 var st = this.tb.fields.item(0);
40992 st.store.removeAll();
40995 var cn = sel.className.split(/\s+/);
40998 if (this.styles['*']) {
41000 Roo.each(this.styles['*'], function(v) {
41001 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
41004 if (this.styles[tn]) {
41005 Roo.each(this.styles[tn], function(v) {
41006 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
41010 st.store.loadData(avs);
41014 // flag our selected Node.
41015 this.tb.selectedNode = sel;
41018 Roo.menu.MenuMgr.hideAll();
41022 if (!updateFooter) {
41025 // update the footer
41029 this.footerEls = ans.reverse();
41030 Roo.each(this.footerEls, function(a,i) {
41031 if (!a) { return; }
41032 html += html.length ? ' > ' : '';
41034 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
41039 var sz = this.footDisp.up('td').getSize();
41040 this.footDisp.dom.style.width = (sz.width -10) + 'px';
41041 this.footDisp.dom.style.marginLeft = '5px';
41043 this.footDisp.dom.style.overflow = 'hidden';
41045 this.footDisp.dom.innerHTML = html;
41047 //this.editorsyncValue();
41052 onDestroy : function(){
41055 this.tb.items.each(function(item){
41057 item.menu.removeAll();
41059 item.menu.el.destroy();
41067 onFirstFocus: function() {
41068 // need to do this for all the toolbars..
41069 this.tb.items.each(function(item){
41073 buildToolbar: function(tlist, nm)
41075 var editor = this.editor;
41076 // create a new element.
41077 var wdiv = editor.wrap.createChild({
41079 }, editor.wrap.dom.firstChild.nextSibling, true);
41082 var tb = new Roo.Toolbar(wdiv);
41085 tb.add(nm+ ": ");
41088 for(var i in this.styles) {
41093 if (styles && styles.length) {
41095 // this needs a multi-select checkbox...
41096 tb.addField( new Roo.form.ComboBox({
41097 store: new Roo.data.SimpleStore({
41099 fields: ['val', 'selected'],
41102 name : 'className',
41103 displayField:'val',
41107 triggerAction: 'all',
41108 emptyText:'Select Style',
41109 selectOnFocus:true,
41112 'select': function(c, r, i) {
41113 // initial support only for on class per el..
41114 tb.selectedNode.className = r ? r.get('val') : '';
41115 editor.syncValue();
41124 for (var i in tlist) {
41126 var item = tlist[i];
41127 tb.add(item.title + ": ");
41133 // opts == pulldown..
41134 tb.addField( new Roo.form.ComboBox({
41135 store: new Roo.data.SimpleStore({
41141 displayField:'val',
41145 triggerAction: 'all',
41146 emptyText:'Select',
41147 selectOnFocus:true,
41148 width: item.width ? item.width : 130,
41150 'select': function(c, r, i) {
41151 tb.selectedNode.setAttribute(c.name, r.get('val'));
41160 tb.addField( new Roo.form.TextField({
41163 //allowBlank:false,
41168 tb.addField( new Roo.form.TextField({
41174 'change' : function(f, nv, ov) {
41175 tb.selectedNode.setAttribute(f.name, nv);
41181 tb.el.on('click', function(e){
41182 e.preventDefault(); // what does this do?
41184 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
41187 // dont need to disable them... as they will get hidden
41192 buildFooter : function()
41195 var fel = this.editor.wrap.createChild();
41196 this.footer = new Roo.Toolbar(fel);
41197 // toolbar has scrolly on left / right?
41198 var footDisp= new Roo.Toolbar.Fill();
41204 handler : function() {
41205 _t.footDisp.scrollTo('left',0,true)
41209 this.footer.add( footDisp );
41214 handler : function() {
41216 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
41220 var fel = Roo.get(footDisp.el);
41221 fel.addClass('x-editor-context');
41222 this.footDispWrap = fel;
41223 this.footDispWrap.overflow = 'hidden';
41225 this.footDisp = fel.createChild();
41226 this.footDispWrap.on('click', this.onContextClick, this)
41230 onContextClick : function (ev,dom)
41232 ev.preventDefault();
41233 var cn = dom.className;
41235 if (!cn.match(/x-ed-loc-/)) {
41238 var n = cn.split('-').pop();
41239 var ans = this.footerEls;
41243 var range = this.editor.createRange();
41245 range.selectNodeContents(sel);
41246 //range.selectNode(sel);
41249 var selection = this.editor.getSelection();
41250 selection.removeAllRanges();
41251 selection.addRange(range);
41255 this.updateToolbar(null, null, sel);
41272 * Ext JS Library 1.1.1
41273 * Copyright(c) 2006-2007, Ext JS, LLC.
41275 * Originally Released Under LGPL - original licence link has changed is not relivant.
41278 * <script type="text/javascript">
41282 * @class Roo.form.BasicForm
41283 * @extends Roo.util.Observable
41284 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
41286 * @param {String/HTMLElement/Roo.Element} el The form element or its id
41287 * @param {Object} config Configuration options
41289 Roo.form.BasicForm = function(el, config){
41290 this.allItems = [];
41291 this.childForms = [];
41292 Roo.apply(this, config);
41294 * The Roo.form.Field items in this form.
41295 * @type MixedCollection
41299 this.items = new Roo.util.MixedCollection(false, function(o){
41300 return o.id || (o.id = Roo.id());
41304 * @event beforeaction
41305 * Fires before any action is performed. Return false to cancel the action.
41306 * @param {Form} this
41307 * @param {Action} action The action to be performed
41309 beforeaction: true,
41311 * @event actionfailed
41312 * Fires when an action fails.
41313 * @param {Form} this
41314 * @param {Action} action The action that failed
41316 actionfailed : true,
41318 * @event actioncomplete
41319 * Fires when an action is completed.
41320 * @param {Form} this
41321 * @param {Action} action The action that completed
41323 actioncomplete : true
41328 Roo.form.BasicForm.superclass.constructor.call(this);
41331 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
41333 * @cfg {String} method
41334 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
41337 * @cfg {DataReader} reader
41338 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
41339 * This is optional as there is built-in support for processing JSON.
41342 * @cfg {DataReader} errorReader
41343 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
41344 * This is completely optional as there is built-in support for processing JSON.
41347 * @cfg {String} url
41348 * The URL to use for form actions if one isn't supplied in the action options.
41351 * @cfg {Boolean} fileUpload
41352 * Set to true if this form is a file upload.
41356 * @cfg {Object} baseParams
41357 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
41362 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
41367 activeAction : null,
41370 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
41371 * or setValues() data instead of when the form was first created.
41373 trackResetOnLoad : false,
41377 * childForms - used for multi-tab forms
41380 childForms : false,
41383 * allItems - full list of fields.
41389 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
41390 * element by passing it or its id or mask the form itself by passing in true.
41393 waitMsgTarget : false,
41396 initEl : function(el){
41397 this.el = Roo.get(el);
41398 this.id = this.el.id || Roo.id();
41399 this.el.on('submit', this.onSubmit, this);
41400 this.el.addClass('x-form');
41404 onSubmit : function(e){
41409 * Returns true if client-side validation on the form is successful.
41412 isValid : function(){
41414 this.items.each(function(f){
41423 * Returns true if any fields in this form have changed since their original load.
41426 isDirty : function(){
41428 this.items.each(function(f){
41438 * Performs a predefined action (submit or load) or custom actions you define on this form.
41439 * @param {String} actionName The name of the action type
41440 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
41441 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
41442 * accept other config options):
41444 Property Type Description
41445 ---------------- --------------- ----------------------------------------------------------------------------------
41446 url String The url for the action (defaults to the form's url)
41447 method String The form method to use (defaults to the form's method, or POST if not defined)
41448 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
41449 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
41450 validate the form on the client (defaults to false)
41452 * @return {BasicForm} this
41454 doAction : function(action, options){
41455 if(typeof action == 'string'){
41456 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
41458 if(this.fireEvent('beforeaction', this, action) !== false){
41459 this.beforeAction(action);
41460 action.run.defer(100, action);
41466 * Shortcut to do a submit action.
41467 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41468 * @return {BasicForm} this
41470 submit : function(options){
41471 this.doAction('submit', options);
41476 * Shortcut to do a load action.
41477 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41478 * @return {BasicForm} this
41480 load : function(options){
41481 this.doAction('load', options);
41486 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
41487 * @param {Record} record The record to edit
41488 * @return {BasicForm} this
41490 updateRecord : function(record){
41491 record.beginEdit();
41492 var fs = record.fields;
41493 fs.each(function(f){
41494 var field = this.findField(f.name);
41496 record.set(f.name, field.getValue());
41504 * Loads an Roo.data.Record into this form.
41505 * @param {Record} record The record to load
41506 * @return {BasicForm} this
41508 loadRecord : function(record){
41509 this.setValues(record.data);
41514 beforeAction : function(action){
41515 var o = action.options;
41518 if(this.waitMsgTarget === true){
41519 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
41520 }else if(this.waitMsgTarget){
41521 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
41522 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
41524 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
41530 afterAction : function(action, success){
41531 this.activeAction = null;
41532 var o = action.options;
41534 if(this.waitMsgTarget === true){
41536 }else if(this.waitMsgTarget){
41537 this.waitMsgTarget.unmask();
41539 Roo.MessageBox.updateProgress(1);
41540 Roo.MessageBox.hide();
41547 Roo.callback(o.success, o.scope, [this, action]);
41548 this.fireEvent('actioncomplete', this, action);
41552 // failure condition..
41553 // we have a scenario where updates need confirming.
41554 // eg. if a locking scenario exists..
41555 // we look for { errors : { needs_confirm : true }} in the response.
41557 (typeof(action.result) != 'undefined') != 'undefined') &&
41558 (typeof(action.result.errors) != 'undefined') &&
41559 (typeof(action.result.errors.needs_confirm) != 'undefined')
41562 Roo.MessageBox.confirm(
41563 "Change requires confirmation",
41564 action.result.errorMsg,
41569 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
41579 Roo.callback(o.failure, o.scope, [this, action]);
41580 // show an error message if no failed handler is set..
41581 if (!this.hasListener('actionfailed')) {
41582 Roo.MessageBox.alert("Error",
41583 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
41584 action.result.errorMsg :
41585 "Saving Failed, please check your entries or try again"
41589 this.fireEvent('actionfailed', this, action);
41595 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
41596 * @param {String} id The value to search for
41599 findField : function(id){
41600 var field = this.items.get(id);
41602 this.items.each(function(f){
41603 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
41609 return field || null;
41613 * Add a secondary form to this one,
41614 * Used to provide tabbed forms. One form is primary, with hidden values
41615 * which mirror the elements from the other forms.
41617 * @param {Roo.form.Form} form to add.
41620 addForm : function(form)
41623 if (this.childForms.indexOf(form) > -1) {
41627 this.childForms.push(form);
41629 Roo.each(form.allItems, function (fe) {
41631 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
41632 if (this.findField(n)) { // already added..
41635 var add = new Roo.form.Hidden({
41638 add.render(this.el);
41645 * Mark fields in this form invalid in bulk.
41646 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
41647 * @return {BasicForm} this
41649 markInvalid : function(errors){
41650 if(errors instanceof Array){
41651 for(var i = 0, len = errors.length; i < len; i++){
41652 var fieldError = errors[i];
41653 var f = this.findField(fieldError.id);
41655 f.markInvalid(fieldError.msg);
41661 if(typeof errors[id] != 'function' && (field = this.findField(id))){
41662 field.markInvalid(errors[id]);
41666 Roo.each(this.childForms || [], function (f) {
41667 f.markInvalid(errors);
41674 * Set values for fields in this form in bulk.
41675 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
41676 * @return {BasicForm} this
41678 setValues : function(values){
41679 if(values instanceof Array){ // array of objects
41680 for(var i = 0, len = values.length; i < len; i++){
41682 var f = this.findField(v.id);
41684 f.setValue(v.value);
41685 if(this.trackResetOnLoad){
41686 f.originalValue = f.getValue();
41690 }else{ // object hash
41693 if(typeof values[id] != 'function' && (field = this.findField(id))){
41695 if (field.setFromData &&
41696 field.valueField &&
41697 field.displayField &&
41698 // combos' with local stores can
41699 // be queried via setValue()
41700 // to set their value..
41701 (field.store && !field.store.isLocal)
41705 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
41706 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
41707 field.setFromData(sd);
41710 field.setValue(values[id]);
41714 if(this.trackResetOnLoad){
41715 field.originalValue = field.getValue();
41721 Roo.each(this.childForms || [], function (f) {
41722 f.setValues(values);
41729 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
41730 * they are returned as an array.
41731 * @param {Boolean} asString
41734 getValues : function(asString){
41735 if (this.childForms) {
41736 // copy values from the child forms
41737 Roo.each(this.childForms, function (f) {
41738 this.setValues(f.getValues());
41744 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
41745 if(asString === true){
41748 return Roo.urlDecode(fs);
41752 * Returns the fields in this form as an object with key/value pairs.
41753 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
41756 getFieldValues : function(with_hidden)
41758 if (this.childForms) {
41759 // copy values from the child forms
41760 // should this call getFieldValues - probably not as we do not currently copy
41761 // hidden fields when we generate..
41762 Roo.each(this.childForms, function (f) {
41763 this.setValues(f.getValues());
41768 this.items.each(function(f){
41769 if (!f.getName()) {
41772 var v = f.getValue();
41773 // not sure if this supported any more..
41774 if ((typeof(v) == 'object') && f.getRawValue) {
41775 v = f.getRawValue() ; // dates..
41777 // combo boxes where name != hiddenName...
41778 if (f.name != f.getName()) {
41779 ret[f.name] = f.getRawValue();
41781 ret[f.getName()] = v;
41788 * Clears all invalid messages in this form.
41789 * @return {BasicForm} this
41791 clearInvalid : function(){
41792 this.items.each(function(f){
41796 Roo.each(this.childForms || [], function (f) {
41805 * Resets this form.
41806 * @return {BasicForm} this
41808 reset : function(){
41809 this.items.each(function(f){
41813 Roo.each(this.childForms || [], function (f) {
41822 * Add Roo.form components to this form.
41823 * @param {Field} field1
41824 * @param {Field} field2 (optional)
41825 * @param {Field} etc (optional)
41826 * @return {BasicForm} this
41829 this.items.addAll(Array.prototype.slice.call(arguments, 0));
41835 * Removes a field from the items collection (does NOT remove its markup).
41836 * @param {Field} field
41837 * @return {BasicForm} this
41839 remove : function(field){
41840 this.items.remove(field);
41845 * Looks at the fields in this form, checks them for an id attribute,
41846 * and calls applyTo on the existing dom element with that id.
41847 * @return {BasicForm} this
41849 render : function(){
41850 this.items.each(function(f){
41851 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
41859 * Calls {@link Ext#apply} for all fields in this form with the passed object.
41860 * @param {Object} values
41861 * @return {BasicForm} this
41863 applyToFields : function(o){
41864 this.items.each(function(f){
41871 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
41872 * @param {Object} values
41873 * @return {BasicForm} this
41875 applyIfToFields : function(o){
41876 this.items.each(function(f){
41884 Roo.BasicForm = Roo.form.BasicForm;/*
41886 * Ext JS Library 1.1.1
41887 * Copyright(c) 2006-2007, Ext JS, LLC.
41889 * Originally Released Under LGPL - original licence link has changed is not relivant.
41892 * <script type="text/javascript">
41896 * @class Roo.form.Form
41897 * @extends Roo.form.BasicForm
41898 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
41900 * @param {Object} config Configuration options
41902 Roo.form.Form = function(config){
41904 if (config.items) {
41905 xitems = config.items;
41906 delete config.items;
41910 Roo.form.Form.superclass.constructor.call(this, null, config);
41911 this.url = this.url || this.action;
41913 this.root = new Roo.form.Layout(Roo.applyIf({
41917 this.active = this.root;
41919 * Array of all the buttons that have been added to this form via {@link addButton}
41923 this.allItems = [];
41926 * @event clientvalidation
41927 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41928 * @param {Form} this
41929 * @param {Boolean} valid true if the form has passed client-side validation
41931 clientvalidation: true,
41934 * Fires when the form is rendered
41935 * @param {Roo.form.Form} form
41940 if (this.progressUrl) {
41941 // push a hidden field onto the list of fields..
41945 name : 'UPLOAD_IDENTIFIER'
41950 Roo.each(xitems, this.addxtype, this);
41956 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41958 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41961 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41964 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41966 buttonAlign:'center',
41969 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41974 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41975 * This property cascades to child containers if not set.
41980 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41981 * fires a looping event with that state. This is required to bind buttons to the valid
41982 * state using the config value formBind:true on the button.
41984 monitorValid : false,
41987 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41992 * @cfg {String} progressUrl - Url to return progress data
41995 progressUrl : false,
41998 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41999 * fields are added and the column is closed. If no fields are passed the column remains open
42000 * until end() is called.
42001 * @param {Object} config The config to pass to the column
42002 * @param {Field} field1 (optional)
42003 * @param {Field} field2 (optional)
42004 * @param {Field} etc (optional)
42005 * @return Column The column container object
42007 column : function(c){
42008 var col = new Roo.form.Column(c);
42010 if(arguments.length > 1){ // duplicate code required because of Opera
42011 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42018 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
42019 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
42020 * until end() is called.
42021 * @param {Object} config The config to pass to the fieldset
42022 * @param {Field} field1 (optional)
42023 * @param {Field} field2 (optional)
42024 * @param {Field} etc (optional)
42025 * @return FieldSet The fieldset container object
42027 fieldset : function(c){
42028 var fs = new Roo.form.FieldSet(c);
42030 if(arguments.length > 1){ // duplicate code required because of Opera
42031 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42038 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
42039 * fields are added and the container is closed. If no fields are passed the container remains open
42040 * until end() is called.
42041 * @param {Object} config The config to pass to the Layout
42042 * @param {Field} field1 (optional)
42043 * @param {Field} field2 (optional)
42044 * @param {Field} etc (optional)
42045 * @return Layout The container object
42047 container : function(c){
42048 var l = new Roo.form.Layout(c);
42050 if(arguments.length > 1){ // duplicate code required because of Opera
42051 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42058 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
42059 * @param {Object} container A Roo.form.Layout or subclass of Layout
42060 * @return {Form} this
42062 start : function(c){
42063 // cascade label info
42064 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
42065 this.active.stack.push(c);
42066 c.ownerCt = this.active;
42072 * Closes the current open container
42073 * @return {Form} this
42076 if(this.active == this.root){
42079 this.active = this.active.ownerCt;
42084 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
42085 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
42086 * as the label of the field.
42087 * @param {Field} field1
42088 * @param {Field} field2 (optional)
42089 * @param {Field} etc. (optional)
42090 * @return {Form} this
42093 this.active.stack.push.apply(this.active.stack, arguments);
42094 this.allItems.push.apply(this.allItems,arguments);
42096 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
42097 if(a[i].isFormField){
42102 Roo.form.Form.superclass.add.apply(this, r);
42112 * Find any element that has been added to a form, using it's ID or name
42113 * This can include framesets, columns etc. along with regular fields..
42114 * @param {String} id - id or name to find.
42116 * @return {Element} e - or false if nothing found.
42118 findbyId : function(id)
42124 Roo.each(this.allItems, function(f){
42125 if (f.id == id || f.name == id ){
42136 * Render this form into the passed container. This should only be called once!
42137 * @param {String/HTMLElement/Element} container The element this component should be rendered into
42138 * @return {Form} this
42140 render : function(ct)
42146 var o = this.autoCreate || {
42148 method : this.method || 'POST',
42149 id : this.id || Roo.id()
42151 this.initEl(ct.createChild(o));
42153 this.root.render(this.el);
42157 this.items.each(function(f){
42158 f.render('x-form-el-'+f.id);
42161 if(this.buttons.length > 0){
42162 // tables are required to maintain order and for correct IE layout
42163 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
42164 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
42165 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
42167 var tr = tb.getElementsByTagName('tr')[0];
42168 for(var i = 0, len = this.buttons.length; i < len; i++) {
42169 var b = this.buttons[i];
42170 var td = document.createElement('td');
42171 td.className = 'x-form-btn-td';
42172 b.render(tr.appendChild(td));
42175 if(this.monitorValid){ // initialize after render
42176 this.startMonitoring();
42178 this.fireEvent('rendered', this);
42183 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
42184 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
42185 * object or a valid Roo.DomHelper element config
42186 * @param {Function} handler The function called when the button is clicked
42187 * @param {Object} scope (optional) The scope of the handler function
42188 * @return {Roo.Button}
42190 addButton : function(config, handler, scope){
42194 minWidth: this.minButtonWidth,
42197 if(typeof config == "string"){
42200 Roo.apply(bc, config);
42202 var btn = new Roo.Button(null, bc);
42203 this.buttons.push(btn);
42208 * Adds a series of form elements (using the xtype property as the factory method.
42209 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
42210 * @param {Object} config
42213 addxtype : function()
42215 var ar = Array.prototype.slice.call(arguments, 0);
42217 for(var i = 0; i < ar.length; i++) {
42219 continue; // skip -- if this happends something invalid got sent, we
42220 // should ignore it, as basically that interface element will not show up
42221 // and that should be pretty obvious!!
42224 if (Roo.form[ar[i].xtype]) {
42226 var fe = Roo.factory(ar[i], Roo.form);
42232 fe.store.form = this;
42237 this.allItems.push(fe);
42238 if (fe.items && fe.addxtype) {
42239 fe.addxtype.apply(fe, fe.items);
42249 // console.log('adding ' + ar[i].xtype);
42251 if (ar[i].xtype == 'Button') {
42252 //console.log('adding button');
42253 //console.log(ar[i]);
42254 this.addButton(ar[i]);
42255 this.allItems.push(fe);
42259 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
42260 alert('end is not supported on xtype any more, use items');
42262 // //console.log('adding end');
42270 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
42271 * option "monitorValid"
42273 startMonitoring : function(){
42276 Roo.TaskMgr.start({
42277 run : this.bindHandler,
42278 interval : this.monitorPoll || 200,
42285 * Stops monitoring of the valid state of this form
42287 stopMonitoring : function(){
42288 this.bound = false;
42292 bindHandler : function(){
42294 return false; // stops binding
42297 this.items.each(function(f){
42298 if(!f.isValid(true)){
42303 for(var i = 0, len = this.buttons.length; i < len; i++){
42304 var btn = this.buttons[i];
42305 if(btn.formBind === true && btn.disabled === valid){
42306 btn.setDisabled(!valid);
42309 this.fireEvent('clientvalidation', this, valid);
42323 Roo.Form = Roo.form.Form;
42326 * Ext JS Library 1.1.1
42327 * Copyright(c) 2006-2007, Ext JS, LLC.
42329 * Originally Released Under LGPL - original licence link has changed is not relivant.
42332 * <script type="text/javascript">
42336 * @class Roo.form.Action
42337 * Internal Class used to handle form actions
42339 * @param {Roo.form.BasicForm} el The form element or its id
42340 * @param {Object} config Configuration options
42344 // define the action interface
42345 Roo.form.Action = function(form, options){
42347 this.options = options || {};
42350 * Client Validation Failed
42353 Roo.form.Action.CLIENT_INVALID = 'client';
42355 * Server Validation Failed
42358 Roo.form.Action.SERVER_INVALID = 'server';
42360 * Connect to Server Failed
42363 Roo.form.Action.CONNECT_FAILURE = 'connect';
42365 * Reading Data from Server Failed
42368 Roo.form.Action.LOAD_FAILURE = 'load';
42370 Roo.form.Action.prototype = {
42372 failureType : undefined,
42373 response : undefined,
42374 result : undefined,
42376 // interface method
42377 run : function(options){
42381 // interface method
42382 success : function(response){
42386 // interface method
42387 handleResponse : function(response){
42391 // default connection failure
42392 failure : function(response){
42394 this.response = response;
42395 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42396 this.form.afterAction(this, false);
42399 processResponse : function(response){
42400 this.response = response;
42401 if(!response.responseText){
42404 this.result = this.handleResponse(response);
42405 return this.result;
42408 // utility functions used internally
42409 getUrl : function(appendParams){
42410 var url = this.options.url || this.form.url || this.form.el.dom.action;
42412 var p = this.getParams();
42414 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
42420 getMethod : function(){
42421 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
42424 getParams : function(){
42425 var bp = this.form.baseParams;
42426 var p = this.options.params;
42428 if(typeof p == "object"){
42429 p = Roo.urlEncode(Roo.applyIf(p, bp));
42430 }else if(typeof p == 'string' && bp){
42431 p += '&' + Roo.urlEncode(bp);
42434 p = Roo.urlEncode(bp);
42439 createCallback : function(){
42441 success: this.success,
42442 failure: this.failure,
42444 timeout: (this.form.timeout*1000),
42445 upload: this.form.fileUpload ? this.success : undefined
42450 Roo.form.Action.Submit = function(form, options){
42451 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
42454 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
42457 haveProgress : false,
42458 uploadComplete : false,
42460 // uploadProgress indicator.
42461 uploadProgress : function()
42463 if (!this.form.progressUrl) {
42467 if (!this.haveProgress) {
42468 Roo.MessageBox.progress("Uploading", "Uploading");
42470 if (this.uploadComplete) {
42471 Roo.MessageBox.hide();
42475 this.haveProgress = true;
42477 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
42479 var c = new Roo.data.Connection();
42481 url : this.form.progressUrl,
42486 success : function(req){
42487 //console.log(data);
42491 rdata = Roo.decode(req.responseText)
42493 Roo.log("Invalid data from server..");
42497 if (!rdata || !rdata.success) {
42501 var data = rdata.data;
42503 if (this.uploadComplete) {
42504 Roo.MessageBox.hide();
42509 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
42510 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
42513 this.uploadProgress.defer(2000,this);
42516 failure: function(data) {
42517 Roo.log('progress url failed ');
42528 // run get Values on the form, so it syncs any secondary forms.
42529 this.form.getValues();
42531 var o = this.options;
42532 var method = this.getMethod();
42533 var isPost = method == 'POST';
42534 if(o.clientValidation === false || this.form.isValid()){
42536 if (this.form.progressUrl) {
42537 this.form.findField('UPLOAD_IDENTIFIER').setValue(
42538 (new Date() * 1) + '' + Math.random());
42543 Roo.Ajax.request(Roo.apply(this.createCallback(), {
42544 form:this.form.el.dom,
42545 url:this.getUrl(!isPost),
42547 params:isPost ? this.getParams() : null,
42548 isUpload: this.form.fileUpload
42551 this.uploadProgress();
42553 }else if (o.clientValidation !== false){ // client validation failed
42554 this.failureType = Roo.form.Action.CLIENT_INVALID;
42555 this.form.afterAction(this, false);
42559 success : function(response)
42561 this.uploadComplete= true;
42562 if (this.haveProgress) {
42563 Roo.MessageBox.hide();
42567 var result = this.processResponse(response);
42568 if(result === true || result.success){
42569 this.form.afterAction(this, true);
42573 this.form.markInvalid(result.errors);
42574 this.failureType = Roo.form.Action.SERVER_INVALID;
42576 this.form.afterAction(this, false);
42578 failure : function(response)
42580 this.uploadComplete= true;
42581 if (this.haveProgress) {
42582 Roo.MessageBox.hide();
42585 this.response = response;
42586 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42587 this.form.afterAction(this, false);
42590 handleResponse : function(response){
42591 if(this.form.errorReader){
42592 var rs = this.form.errorReader.read(response);
42595 for(var i = 0, len = rs.records.length; i < len; i++) {
42596 var r = rs.records[i];
42597 errors[i] = r.data;
42600 if(errors.length < 1){
42604 success : rs.success,
42610 ret = Roo.decode(response.responseText);
42614 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
42624 Roo.form.Action.Load = function(form, options){
42625 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
42626 this.reader = this.form.reader;
42629 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
42634 Roo.Ajax.request(Roo.apply(
42635 this.createCallback(), {
42636 method:this.getMethod(),
42637 url:this.getUrl(false),
42638 params:this.getParams()
42642 success : function(response){
42644 var result = this.processResponse(response);
42645 if(result === true || !result.success || !result.data){
42646 this.failureType = Roo.form.Action.LOAD_FAILURE;
42647 this.form.afterAction(this, false);
42650 this.form.clearInvalid();
42651 this.form.setValues(result.data);
42652 this.form.afterAction(this, true);
42655 handleResponse : function(response){
42656 if(this.form.reader){
42657 var rs = this.form.reader.read(response);
42658 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
42660 success : rs.success,
42664 return Roo.decode(response.responseText);
42668 Roo.form.Action.ACTION_TYPES = {
42669 'load' : Roo.form.Action.Load,
42670 'submit' : Roo.form.Action.Submit
42673 * Ext JS Library 1.1.1
42674 * Copyright(c) 2006-2007, Ext JS, LLC.
42676 * Originally Released Under LGPL - original licence link has changed is not relivant.
42679 * <script type="text/javascript">
42683 * @class Roo.form.Layout
42684 * @extends Roo.Component
42685 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
42687 * @param {Object} config Configuration options
42689 Roo.form.Layout = function(config){
42691 if (config.items) {
42692 xitems = config.items;
42693 delete config.items;
42695 Roo.form.Layout.superclass.constructor.call(this, config);
42697 Roo.each(xitems, this.addxtype, this);
42701 Roo.extend(Roo.form.Layout, Roo.Component, {
42703 * @cfg {String/Object} autoCreate
42704 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
42707 * @cfg {String/Object/Function} style
42708 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
42709 * a function which returns such a specification.
42712 * @cfg {String} labelAlign
42713 * Valid values are "left," "top" and "right" (defaults to "left")
42716 * @cfg {Number} labelWidth
42717 * Fixed width in pixels of all field labels (defaults to undefined)
42720 * @cfg {Boolean} clear
42721 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
42725 * @cfg {String} labelSeparator
42726 * The separator to use after field labels (defaults to ':')
42728 labelSeparator : ':',
42730 * @cfg {Boolean} hideLabels
42731 * True to suppress the display of field labels in this layout (defaults to false)
42733 hideLabels : false,
42736 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
42741 onRender : function(ct, position){
42742 if(this.el){ // from markup
42743 this.el = Roo.get(this.el);
42744 }else { // generate
42745 var cfg = this.getAutoCreate();
42746 this.el = ct.createChild(cfg, position);
42749 this.el.applyStyles(this.style);
42751 if(this.labelAlign){
42752 this.el.addClass('x-form-label-'+this.labelAlign);
42754 if(this.hideLabels){
42755 this.labelStyle = "display:none";
42756 this.elementStyle = "padding-left:0;";
42758 if(typeof this.labelWidth == 'number'){
42759 this.labelStyle = "width:"+this.labelWidth+"px;";
42760 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
42762 if(this.labelAlign == 'top'){
42763 this.labelStyle = "width:auto;";
42764 this.elementStyle = "padding-left:0;";
42767 var stack = this.stack;
42768 var slen = stack.length;
42770 if(!this.fieldTpl){
42771 var t = new Roo.Template(
42772 '<div class="x-form-item {5}">',
42773 '<label for="{0}" style="{2}">{1}{4}</label>',
42774 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42776 '</div><div class="x-form-clear-left"></div>'
42778 t.disableFormats = true;
42780 Roo.form.Layout.prototype.fieldTpl = t;
42782 for(var i = 0; i < slen; i++) {
42783 if(stack[i].isFormField){
42784 this.renderField(stack[i]);
42786 this.renderComponent(stack[i]);
42791 this.el.createChild({cls:'x-form-clear'});
42796 renderField : function(f){
42797 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
42800 f.labelStyle||this.labelStyle||'', //2
42801 this.elementStyle||'', //3
42802 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
42803 f.itemCls||this.itemCls||'' //5
42804 ], true).getPrevSibling());
42808 renderComponent : function(c){
42809 c.render(c.isLayout ? this.el : this.el.createChild());
42812 * Adds a object form elements (using the xtype property as the factory method.)
42813 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
42814 * @param {Object} config
42816 addxtype : function(o)
42818 // create the lement.
42819 o.form = this.form;
42820 var fe = Roo.factory(o, Roo.form);
42821 this.form.allItems.push(fe);
42822 this.stack.push(fe);
42824 if (fe.isFormField) {
42825 this.form.items.add(fe);
42833 * @class Roo.form.Column
42834 * @extends Roo.form.Layout
42835 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
42837 * @param {Object} config Configuration options
42839 Roo.form.Column = function(config){
42840 Roo.form.Column.superclass.constructor.call(this, config);
42843 Roo.extend(Roo.form.Column, Roo.form.Layout, {
42845 * @cfg {Number/String} width
42846 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42849 * @cfg {String/Object} autoCreate
42850 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
42854 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
42857 onRender : function(ct, position){
42858 Roo.form.Column.superclass.onRender.call(this, ct, position);
42860 this.el.setWidth(this.width);
42867 * @class Roo.form.Row
42868 * @extends Roo.form.Layout
42869 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
42871 * @param {Object} config Configuration options
42875 Roo.form.Row = function(config){
42876 Roo.form.Row.superclass.constructor.call(this, config);
42879 Roo.extend(Roo.form.Row, Roo.form.Layout, {
42881 * @cfg {Number/String} width
42882 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42885 * @cfg {Number/String} height
42886 * The fixed height of the column in pixels or CSS value (defaults to "auto")
42888 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
42892 onRender : function(ct, position){
42893 //console.log('row render');
42895 var t = new Roo.Template(
42896 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
42897 '<label for="{0}" style="{2}">{1}{4}</label>',
42898 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42902 t.disableFormats = true;
42904 Roo.form.Layout.prototype.rowTpl = t;
42906 this.fieldTpl = this.rowTpl;
42908 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
42909 var labelWidth = 100;
42911 if ((this.labelAlign != 'top')) {
42912 if (typeof this.labelWidth == 'number') {
42913 labelWidth = this.labelWidth
42915 this.padWidth = 20 + labelWidth;
42919 Roo.form.Column.superclass.onRender.call(this, ct, position);
42921 this.el.setWidth(this.width);
42924 this.el.setHeight(this.height);
42929 renderField : function(f){
42930 f.fieldEl = this.fieldTpl.append(this.el, [
42931 f.id, f.fieldLabel,
42932 f.labelStyle||this.labelStyle||'',
42933 this.elementStyle||'',
42934 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42935 f.itemCls||this.itemCls||'',
42936 f.width ? f.width + this.padWidth : 160 + this.padWidth
42943 * @class Roo.form.FieldSet
42944 * @extends Roo.form.Layout
42945 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42947 * @param {Object} config Configuration options
42949 Roo.form.FieldSet = function(config){
42950 Roo.form.FieldSet.superclass.constructor.call(this, config);
42953 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42955 * @cfg {String} legend
42956 * The text to display as the legend for the FieldSet (defaults to '')
42959 * @cfg {String/Object} autoCreate
42960 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42964 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42967 onRender : function(ct, position){
42968 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42970 this.setLegend(this.legend);
42975 setLegend : function(text){
42977 this.el.child('legend').update(text);
42982 * Ext JS Library 1.1.1
42983 * Copyright(c) 2006-2007, Ext JS, LLC.
42985 * Originally Released Under LGPL - original licence link has changed is not relivant.
42988 * <script type="text/javascript">
42991 * @class Roo.form.VTypes
42992 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42995 Roo.form.VTypes = function(){
42996 // closure these in so they are only created once.
42997 var alpha = /^[a-zA-Z_]+$/;
42998 var alphanum = /^[a-zA-Z0-9_]+$/;
42999 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
43000 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
43002 // All these messages and functions are configurable
43005 * The function used to validate email addresses
43006 * @param {String} value The email address
43008 'email' : function(v){
43009 return email.test(v);
43012 * The error text to display when the email validation function returns false
43015 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
43017 * The keystroke filter mask to be applied on email input
43020 'emailMask' : /[a-z0-9_\.\-@]/i,
43023 * The function used to validate URLs
43024 * @param {String} value The URL
43026 'url' : function(v){
43027 return url.test(v);
43030 * The error text to display when the url validation function returns false
43033 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
43036 * The function used to validate alpha values
43037 * @param {String} value The value
43039 'alpha' : function(v){
43040 return alpha.test(v);
43043 * The error text to display when the alpha validation function returns false
43046 'alphaText' : 'This field should only contain letters and _',
43048 * The keystroke filter mask to be applied on alpha input
43051 'alphaMask' : /[a-z_]/i,
43054 * The function used to validate alphanumeric values
43055 * @param {String} value The value
43057 'alphanum' : function(v){
43058 return alphanum.test(v);
43061 * The error text to display when the alphanumeric validation function returns false
43064 'alphanumText' : 'This field should only contain letters, numbers and _',
43066 * The keystroke filter mask to be applied on alphanumeric input
43069 'alphanumMask' : /[a-z0-9_]/i
43071 }();//<script type="text/javascript">
43074 * @class Roo.form.FCKeditor
43075 * @extends Roo.form.TextArea
43076 * Wrapper around the FCKEditor http://www.fckeditor.net
43078 * Creates a new FCKeditor
43079 * @param {Object} config Configuration options
43081 Roo.form.FCKeditor = function(config){
43082 Roo.form.FCKeditor.superclass.constructor.call(this, config);
43085 * @event editorinit
43086 * Fired when the editor is initialized - you can add extra handlers here..
43087 * @param {FCKeditor} this
43088 * @param {Object} the FCK object.
43095 Roo.form.FCKeditor.editors = { };
43096 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
43098 //defaultAutoCreate : {
43099 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
43103 * @cfg {Object} fck options - see fck manual for details.
43108 * @cfg {Object} fck toolbar set (Basic or Default)
43110 toolbarSet : 'Basic',
43112 * @cfg {Object} fck BasePath
43114 basePath : '/fckeditor/',
43122 onRender : function(ct, position)
43125 this.defaultAutoCreate = {
43127 style:"width:300px;height:60px;",
43128 autocomplete: "off"
43131 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
43134 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
43135 if(this.preventScrollbars){
43136 this.el.setStyle("overflow", "hidden");
43138 this.el.setHeight(this.growMin);
43141 //console.log('onrender' + this.getId() );
43142 Roo.form.FCKeditor.editors[this.getId()] = this;
43145 this.replaceTextarea() ;
43149 getEditor : function() {
43150 return this.fckEditor;
43153 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
43154 * @param {Mixed} value The value to set
43158 setValue : function(value)
43160 //console.log('setValue: ' + value);
43162 if(typeof(value) == 'undefined') { // not sure why this is happending...
43165 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
43167 //if(!this.el || !this.getEditor()) {
43168 // this.value = value;
43169 //this.setValue.defer(100,this,[value]);
43173 if(!this.getEditor()) {
43177 this.getEditor().SetData(value);
43184 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
43185 * @return {Mixed} value The field value
43187 getValue : function()
43190 if (this.frame && this.frame.dom.style.display == 'none') {
43191 return Roo.form.FCKeditor.superclass.getValue.call(this);
43194 if(!this.el || !this.getEditor()) {
43196 // this.getValue.defer(100,this);
43201 var value=this.getEditor().GetData();
43202 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
43203 return Roo.form.FCKeditor.superclass.getValue.call(this);
43209 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
43210 * @return {Mixed} value The field value
43212 getRawValue : function()
43214 if (this.frame && this.frame.dom.style.display == 'none') {
43215 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
43218 if(!this.el || !this.getEditor()) {
43219 //this.getRawValue.defer(100,this);
43226 var value=this.getEditor().GetData();
43227 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
43228 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
43232 setSize : function(w,h) {
43236 //if (this.frame && this.frame.dom.style.display == 'none') {
43237 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43240 //if(!this.el || !this.getEditor()) {
43241 // this.setSize.defer(100,this, [w,h]);
43247 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43249 this.frame.dom.setAttribute('width', w);
43250 this.frame.dom.setAttribute('height', h);
43251 this.frame.setSize(w,h);
43255 toggleSourceEdit : function(value) {
43259 this.el.dom.style.display = value ? '' : 'none';
43260 this.frame.dom.style.display = value ? 'none' : '';
43265 focus: function(tag)
43267 if (this.frame.dom.style.display == 'none') {
43268 return Roo.form.FCKeditor.superclass.focus.call(this);
43270 if(!this.el || !this.getEditor()) {
43271 this.focus.defer(100,this, [tag]);
43278 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
43279 this.getEditor().Focus();
43281 if (!this.getEditor().Selection.GetSelection()) {
43282 this.focus.defer(100,this, [tag]);
43287 var r = this.getEditor().EditorDocument.createRange();
43288 r.setStart(tgs[0],0);
43289 r.setEnd(tgs[0],0);
43290 this.getEditor().Selection.GetSelection().removeAllRanges();
43291 this.getEditor().Selection.GetSelection().addRange(r);
43292 this.getEditor().Focus();
43299 replaceTextarea : function()
43301 if ( document.getElementById( this.getId() + '___Frame' ) )
43303 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
43305 // We must check the elements firstly using the Id and then the name.
43306 var oTextarea = document.getElementById( this.getId() );
43308 var colElementsByName = document.getElementsByName( this.getId() ) ;
43310 oTextarea.style.display = 'none' ;
43312 if ( oTextarea.tabIndex ) {
43313 this.TabIndex = oTextarea.tabIndex ;
43316 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
43317 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
43318 this.frame = Roo.get(this.getId() + '___Frame')
43321 _getConfigHtml : function()
43325 for ( var o in this.fckconfig ) {
43326 sConfig += sConfig.length > 0 ? '&' : '';
43327 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
43330 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
43334 _getIFrameHtml : function()
43336 var sFile = 'fckeditor.html' ;
43337 /* no idea what this is about..
43340 if ( (/fcksource=true/i).test( window.top.location.search ) )
43341 sFile = 'fckeditor.original.html' ;
43346 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
43347 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
43350 var html = '<iframe id="' + this.getId() +
43351 '___Frame" src="' + sLink +
43352 '" width="' + this.width +
43353 '" height="' + this.height + '"' +
43354 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
43355 ' frameborder="0" scrolling="no"></iframe>' ;
43360 _insertHtmlBefore : function( html, element )
43362 if ( element.insertAdjacentHTML ) {
43364 element.insertAdjacentHTML( 'beforeBegin', html ) ;
43366 var oRange = document.createRange() ;
43367 oRange.setStartBefore( element ) ;
43368 var oFragment = oRange.createContextualFragment( html );
43369 element.parentNode.insertBefore( oFragment, element ) ;
43382 //Roo.reg('fckeditor', Roo.form.FCKeditor);
43384 function FCKeditor_OnComplete(editorInstance){
43385 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
43386 f.fckEditor = editorInstance;
43387 //console.log("loaded");
43388 f.fireEvent('editorinit', f, editorInstance);
43408 //<script type="text/javascript">
43410 * @class Roo.form.GridField
43411 * @extends Roo.form.Field
43412 * Embed a grid (or editable grid into a form)
43415 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
43417 * xgrid.store = Roo.data.Store
43418 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
43419 * xgrid.store.reader = Roo.data.JsonReader
43423 * Creates a new GridField
43424 * @param {Object} config Configuration options
43426 Roo.form.GridField = function(config){
43427 Roo.form.GridField.superclass.constructor.call(this, config);
43431 Roo.extend(Roo.form.GridField, Roo.form.Field, {
43433 * @cfg {Number} width - used to restrict width of grid..
43437 * @cfg {Number} height - used to restrict height of grid..
43441 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
43447 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43448 * {tag: "input", type: "checkbox", autocomplete: "off"})
43450 // defaultAutoCreate : { tag: 'div' },
43451 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43453 * @cfg {String} addTitle Text to include for adding a title.
43457 onResize : function(){
43458 Roo.form.Field.superclass.onResize.apply(this, arguments);
43461 initEvents : function(){
43462 // Roo.form.Checkbox.superclass.initEvents.call(this);
43463 // has no events...
43468 getResizeEl : function(){
43472 getPositionEl : function(){
43477 onRender : function(ct, position){
43479 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
43480 var style = this.style;
43483 Roo.form.GridField.superclass.onRender.call(this, ct, position);
43484 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
43485 this.viewEl = this.wrap.createChild({ tag: 'div' });
43487 this.viewEl.applyStyles(style);
43490 this.viewEl.setWidth(this.width);
43493 this.viewEl.setHeight(this.height);
43495 //if(this.inputValue !== undefined){
43496 //this.setValue(this.value);
43499 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
43502 this.grid.render();
43503 this.grid.getDataSource().on('remove', this.refreshValue, this);
43504 this.grid.getDataSource().on('update', this.refreshValue, this);
43505 this.grid.on('afteredit', this.refreshValue, this);
43511 * Sets the value of the item.
43512 * @param {String} either an object or a string..
43514 setValue : function(v){
43516 v = v || []; // empty set..
43517 // this does not seem smart - it really only affects memoryproxy grids..
43518 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
43519 var ds = this.grid.getDataSource();
43520 // assumes a json reader..
43522 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
43523 ds.loadData( data);
43525 // clear selection so it does not get stale.
43526 if (this.grid.sm) {
43527 this.grid.sm.clearSelections();
43530 Roo.form.GridField.superclass.setValue.call(this, v);
43531 this.refreshValue();
43532 // should load data in the grid really....
43536 refreshValue: function() {
43538 this.grid.getDataSource().each(function(r) {
43541 this.el.dom.value = Roo.encode(val);
43549 * Ext JS Library 1.1.1
43550 * Copyright(c) 2006-2007, Ext JS, LLC.
43552 * Originally Released Under LGPL - original licence link has changed is not relivant.
43555 * <script type="text/javascript">
43558 * @class Roo.form.DisplayField
43559 * @extends Roo.form.Field
43560 * A generic Field to display non-editable data.
43562 * Creates a new Display Field item.
43563 * @param {Object} config Configuration options
43565 Roo.form.DisplayField = function(config){
43566 Roo.form.DisplayField.superclass.constructor.call(this, config);
43570 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
43571 inputType: 'hidden',
43577 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43579 focusClass : undefined,
43581 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43583 fieldClass: 'x-form-field',
43586 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
43588 valueRenderer: undefined,
43592 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43593 * {tag: "input", type: "checkbox", autocomplete: "off"})
43596 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43598 onResize : function(){
43599 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
43603 initEvents : function(){
43604 // Roo.form.Checkbox.superclass.initEvents.call(this);
43605 // has no events...
43610 getResizeEl : function(){
43614 getPositionEl : function(){
43619 onRender : function(ct, position){
43621 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
43622 //if(this.inputValue !== undefined){
43623 this.wrap = this.el.wrap();
43625 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
43627 if (this.bodyStyle) {
43628 this.viewEl.applyStyles(this.bodyStyle);
43630 //this.viewEl.setStyle('padding', '2px');
43632 this.setValue(this.value);
43637 initValue : Roo.emptyFn,
43642 onClick : function(){
43647 * Sets the checked state of the checkbox.
43648 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
43650 setValue : function(v){
43652 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
43653 // this might be called before we have a dom element..
43654 if (!this.viewEl) {
43657 this.viewEl.dom.innerHTML = html;
43658 Roo.form.DisplayField.superclass.setValue.call(this, v);
43668 * @class Roo.form.DayPicker
43669 * @extends Roo.form.Field
43670 * A Day picker show [M] [T] [W] ....
43672 * Creates a new Day Picker
43673 * @param {Object} config Configuration options
43675 Roo.form.DayPicker= function(config){
43676 Roo.form.DayPicker.superclass.constructor.call(this, config);
43680 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
43682 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43684 focusClass : undefined,
43686 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43688 fieldClass: "x-form-field",
43691 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43692 * {tag: "input", type: "checkbox", autocomplete: "off"})
43694 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43697 actionMode : 'viewEl',
43701 inputType : 'hidden',
43704 inputElement: false, // real input element?
43705 basedOn: false, // ????
43707 isFormField: true, // not sure where this is needed!!!!
43709 onResize : function(){
43710 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43711 if(!this.boxLabel){
43712 this.el.alignTo(this.wrap, 'c-c');
43716 initEvents : function(){
43717 Roo.form.Checkbox.superclass.initEvents.call(this);
43718 this.el.on("click", this.onClick, this);
43719 this.el.on("change", this.onClick, this);
43723 getResizeEl : function(){
43727 getPositionEl : function(){
43733 onRender : function(ct, position){
43734 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43736 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
43738 var r1 = '<table><tr>';
43739 var r2 = '<tr class="x-form-daypick-icons">';
43740 for (var i=0; i < 7; i++) {
43741 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
43742 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
43745 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
43746 viewEl.select('img').on('click', this.onClick, this);
43747 this.viewEl = viewEl;
43750 // this will not work on Chrome!!!
43751 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43752 this.el.on('propertychange', this.setFromHidden, this); //ie
43760 initValue : Roo.emptyFn,
43763 * Returns the checked state of the checkbox.
43764 * @return {Boolean} True if checked, else false
43766 getValue : function(){
43767 return this.el.dom.value;
43772 onClick : function(e){
43773 //this.setChecked(!this.checked);
43774 Roo.get(e.target).toggleClass('x-menu-item-checked');
43775 this.refreshValue();
43776 //if(this.el.dom.checked != this.checked){
43777 // this.setValue(this.el.dom.checked);
43782 refreshValue : function()
43785 this.viewEl.select('img',true).each(function(e,i,n) {
43786 val += e.is(".x-menu-item-checked") ? String(n) : '';
43788 this.setValue(val, true);
43792 * Sets the checked state of the checkbox.
43793 * On is always based on a string comparison between inputValue and the param.
43794 * @param {Boolean/String} value - the value to set
43795 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43797 setValue : function(v,suppressEvent){
43798 if (!this.el.dom) {
43801 var old = this.el.dom.value ;
43802 this.el.dom.value = v;
43803 if (suppressEvent) {
43807 // update display..
43808 this.viewEl.select('img',true).each(function(e,i,n) {
43810 var on = e.is(".x-menu-item-checked");
43811 var newv = v.indexOf(String(n)) > -1;
43813 e.toggleClass('x-menu-item-checked');
43819 this.fireEvent('change', this, v, old);
43824 // handle setting of hidden value by some other method!!?!?
43825 setFromHidden: function()
43830 //console.log("SET FROM HIDDEN");
43831 //alert('setFrom hidden');
43832 this.setValue(this.el.dom.value);
43835 onDestroy : function()
43838 Roo.get(this.viewEl).remove();
43841 Roo.form.DayPicker.superclass.onDestroy.call(this);
43845 * RooJS Library 1.1.1
43846 * Copyright(c) 2008-2011 Alan Knowles
43853 * @class Roo.form.ComboCheck
43854 * @extends Roo.form.ComboBox
43855 * A combobox for multiple select items.
43857 * FIXME - could do with a reset button..
43860 * Create a new ComboCheck
43861 * @param {Object} config Configuration options
43863 Roo.form.ComboCheck = function(config){
43864 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43865 // should verify some data...
43867 // hiddenName = required..
43868 // displayField = required
43869 // valudField == required
43870 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43872 Roo.each(req, function(e) {
43873 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43874 throw "Roo.form.ComboCheck : missing value for: " + e;
43881 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
43886 selectedClass: 'x-menu-item-checked',
43889 onRender : function(ct, position){
43895 var cls = 'x-combo-list';
43898 this.tpl = new Roo.Template({
43899 html : '<div class="'+cls+'-item x-menu-check-item">' +
43900 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
43901 '<span>{' + this.displayField + '}</span>' +
43908 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
43909 this.view.singleSelect = false;
43910 this.view.multiSelect = true;
43911 this.view.toggleSelect = true;
43912 this.pageTb.add(new Roo.Toolbar.Fill(), {
43915 handler: function()
43922 onViewOver : function(e, t){
43928 onViewClick : function(doFocus,index){
43932 select: function () {
43933 //Roo.log("SELECT CALLED");
43936 selectByValue : function(xv, scrollIntoView){
43937 var ar = this.getValueArray();
43940 Roo.each(ar, function(v) {
43941 if(v === undefined || v === null){
43944 var r = this.findRecord(this.valueField, v);
43946 sels.push(this.store.indexOf(r))
43950 this.view.select(sels);
43956 onSelect : function(record, index){
43957 // Roo.log("onselect Called");
43958 // this is only called by the clear button now..
43959 this.view.clearSelections();
43960 this.setValue('[]');
43961 if (this.value != this.valueBefore) {
43962 this.fireEvent('change', this, this.value, this.valueBefore);
43965 getValueArray : function()
43970 //Roo.log(this.value);
43971 if (typeof(this.value) == 'undefined') {
43974 var ar = Roo.decode(this.value);
43975 return ar instanceof Array ? ar : []; //?? valid?
43978 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
43983 expand : function ()
43985 Roo.form.ComboCheck.superclass.expand.call(this);
43986 this.valueBefore = this.value;
43991 collapse : function(){
43992 Roo.form.ComboCheck.superclass.collapse.call(this);
43993 var sl = this.view.getSelectedIndexes();
43994 var st = this.store;
43998 Roo.each(sl, function(i) {
44000 nv.push(r.get(this.valueField));
44002 this.setValue(Roo.encode(nv));
44003 if (this.value != this.valueBefore) {
44005 this.fireEvent('change', this, this.value, this.valueBefore);
44010 setValue : function(v){
44014 var vals = this.getValueArray();
44016 Roo.each(vals, function(k) {
44017 var r = this.findRecord(this.valueField, k);
44019 tv.push(r.data[this.displayField]);
44020 }else if(this.valueNotFoundText !== undefined){
44021 tv.push( this.valueNotFoundText );
44026 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
44027 this.hiddenField.value = v;
44031 });//<script type="text/javasscript">
44035 * @class Roo.DDView
44036 * A DnD enabled version of Roo.View.
44037 * @param {Element/String} container The Element in which to create the View.
44038 * @param {String} tpl The template string used to create the markup for each element of the View
44039 * @param {Object} config The configuration properties. These include all the config options of
44040 * {@link Roo.View} plus some specific to this class.<br>
44042 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
44043 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
44045 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
44046 .x-view-drag-insert-above {
44047 border-top:1px dotted #3366cc;
44049 .x-view-drag-insert-below {
44050 border-bottom:1px dotted #3366cc;
44056 Roo.DDView = function(container, tpl, config) {
44057 Roo.DDView.superclass.constructor.apply(this, arguments);
44058 this.getEl().setStyle("outline", "0px none");
44059 this.getEl().unselectable();
44060 if (this.dragGroup) {
44061 this.setDraggable(this.dragGroup.split(","));
44063 if (this.dropGroup) {
44064 this.setDroppable(this.dropGroup.split(","));
44066 if (this.deletable) {
44067 this.setDeletable();
44069 this.isDirtyFlag = false;
44075 Roo.extend(Roo.DDView, Roo.View, {
44076 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
44077 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
44078 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
44079 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
44083 reset: Roo.emptyFn,
44085 clearInvalid: Roo.form.Field.prototype.clearInvalid,
44087 validate: function() {
44091 destroy: function() {
44092 this.purgeListeners();
44093 this.getEl.removeAllListeners();
44094 this.getEl().remove();
44095 if (this.dragZone) {
44096 if (this.dragZone.destroy) {
44097 this.dragZone.destroy();
44100 if (this.dropZone) {
44101 if (this.dropZone.destroy) {
44102 this.dropZone.destroy();
44107 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
44108 getName: function() {
44112 /** Loads the View from a JSON string representing the Records to put into the Store. */
44113 setValue: function(v) {
44115 throw "DDView.setValue(). DDView must be constructed with a valid Store";
44118 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
44119 this.store.proxy = new Roo.data.MemoryProxy(data);
44123 /** @return {String} a parenthesised list of the ids of the Records in the View. */
44124 getValue: function() {
44126 this.store.each(function(rec) {
44127 result += rec.id + ',';
44129 return result.substr(0, result.length - 1) + ')';
44132 getIds: function() {
44133 var i = 0, result = new Array(this.store.getCount());
44134 this.store.each(function(rec) {
44135 result[i++] = rec.id;
44140 isDirty: function() {
44141 return this.isDirtyFlag;
44145 * Part of the Roo.dd.DropZone interface. If no target node is found, the
44146 * whole Element becomes the target, and this causes the drop gesture to append.
44148 getTargetFromEvent : function(e) {
44149 var target = e.getTarget();
44150 while ((target !== null) && (target.parentNode != this.el.dom)) {
44151 target = target.parentNode;
44154 target = this.el.dom.lastChild || this.el.dom;
44160 * Create the drag data which consists of an object which has the property "ddel" as
44161 * the drag proxy element.
44163 getDragData : function(e) {
44164 var target = this.findItemFromChild(e.getTarget());
44166 this.handleSelection(e);
44167 var selNodes = this.getSelectedNodes();
44170 copy: this.copy || (this.allowCopy && e.ctrlKey),
44174 var selectedIndices = this.getSelectedIndexes();
44175 for (var i = 0; i < selectedIndices.length; i++) {
44176 dragData.records.push(this.store.getAt(selectedIndices[i]));
44178 if (selNodes.length == 1) {
44179 dragData.ddel = target.cloneNode(true); // the div element
44181 var div = document.createElement('div'); // create the multi element drag "ghost"
44182 div.className = 'multi-proxy';
44183 for (var i = 0, len = selNodes.length; i < len; i++) {
44184 div.appendChild(selNodes[i].cloneNode(true));
44186 dragData.ddel = div;
44188 //console.log(dragData)
44189 //console.log(dragData.ddel.innerHTML)
44192 //console.log('nodragData')
44196 /** Specify to which ddGroup items in this DDView may be dragged. */
44197 setDraggable: function(ddGroup) {
44198 if (ddGroup instanceof Array) {
44199 Roo.each(ddGroup, this.setDraggable, this);
44202 if (this.dragZone) {
44203 this.dragZone.addToGroup(ddGroup);
44205 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
44206 containerScroll: true,
44210 // Draggability implies selection. DragZone's mousedown selects the element.
44211 if (!this.multiSelect) { this.singleSelect = true; }
44213 // Wire the DragZone's handlers up to methods in *this*
44214 this.dragZone.getDragData = this.getDragData.createDelegate(this);
44218 /** Specify from which ddGroup this DDView accepts drops. */
44219 setDroppable: function(ddGroup) {
44220 if (ddGroup instanceof Array) {
44221 Roo.each(ddGroup, this.setDroppable, this);
44224 if (this.dropZone) {
44225 this.dropZone.addToGroup(ddGroup);
44227 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
44228 containerScroll: true,
44232 // Wire the DropZone's handlers up to methods in *this*
44233 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
44234 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
44235 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
44236 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
44237 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
44241 /** Decide whether to drop above or below a View node. */
44242 getDropPoint : function(e, n, dd){
44243 if (n == this.el.dom) { return "above"; }
44244 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
44245 var c = t + (b - t) / 2;
44246 var y = Roo.lib.Event.getPageY(e);
44254 onNodeEnter : function(n, dd, e, data){
44258 onNodeOver : function(n, dd, e, data){
44259 var pt = this.getDropPoint(e, n, dd);
44260 // set the insert point style on the target node
44261 var dragElClass = this.dropNotAllowed;
44264 if (pt == "above"){
44265 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
44266 targetElClass = "x-view-drag-insert-above";
44268 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
44269 targetElClass = "x-view-drag-insert-below";
44271 if (this.lastInsertClass != targetElClass){
44272 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
44273 this.lastInsertClass = targetElClass;
44276 return dragElClass;
44279 onNodeOut : function(n, dd, e, data){
44280 this.removeDropIndicators(n);
44283 onNodeDrop : function(n, dd, e, data){
44284 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
44287 var pt = this.getDropPoint(e, n, dd);
44288 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
44289 if (pt == "below") { insertAt++; }
44290 for (var i = 0; i < data.records.length; i++) {
44291 var r = data.records[i];
44292 var dup = this.store.getById(r.id);
44293 if (dup && (dd != this.dragZone)) {
44294 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
44297 this.store.insert(insertAt++, r.copy());
44299 data.source.isDirtyFlag = true;
44301 this.store.insert(insertAt++, r);
44303 this.isDirtyFlag = true;
44306 this.dragZone.cachedTarget = null;
44310 removeDropIndicators : function(n){
44312 Roo.fly(n).removeClass([
44313 "x-view-drag-insert-above",
44314 "x-view-drag-insert-below"]);
44315 this.lastInsertClass = "_noclass";
44320 * Utility method. Add a delete option to the DDView's context menu.
44321 * @param {String} imageUrl The URL of the "delete" icon image.
44323 setDeletable: function(imageUrl) {
44324 if (!this.singleSelect && !this.multiSelect) {
44325 this.singleSelect = true;
44327 var c = this.getContextMenu();
44328 this.contextMenu.on("itemclick", function(item) {
44331 this.remove(this.getSelectedIndexes());
44335 this.contextMenu.add({
44342 /** Return the context menu for this DDView. */
44343 getContextMenu: function() {
44344 if (!this.contextMenu) {
44345 // Create the View's context menu
44346 this.contextMenu = new Roo.menu.Menu({
44347 id: this.id + "-contextmenu"
44349 this.el.on("contextmenu", this.showContextMenu, this);
44351 return this.contextMenu;
44354 disableContextMenu: function() {
44355 if (this.contextMenu) {
44356 this.el.un("contextmenu", this.showContextMenu, this);
44360 showContextMenu: function(e, item) {
44361 item = this.findItemFromChild(e.getTarget());
44364 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
44365 this.contextMenu.showAt(e.getXY());
44370 * Remove {@link Roo.data.Record}s at the specified indices.
44371 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
44373 remove: function(selectedIndices) {
44374 selectedIndices = [].concat(selectedIndices);
44375 for (var i = 0; i < selectedIndices.length; i++) {
44376 var rec = this.store.getAt(selectedIndices[i]);
44377 this.store.remove(rec);
44382 * Double click fires the event, but also, if this is draggable, and there is only one other
44383 * related DropZone, it transfers the selected node.
44385 onDblClick : function(e){
44386 var item = this.findItemFromChild(e.getTarget());
44388 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
44391 if (this.dragGroup) {
44392 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
44393 while (targets.indexOf(this.dropZone) > -1) {
44394 targets.remove(this.dropZone);
44396 if (targets.length == 1) {
44397 this.dragZone.cachedTarget = null;
44398 var el = Roo.get(targets[0].getEl());
44399 var box = el.getBox(true);
44400 targets[0].onNodeDrop(el.dom, {
44402 xy: [box.x, box.y + box.height - 1]
44403 }, null, this.getDragData(e));
44409 handleSelection: function(e) {
44410 this.dragZone.cachedTarget = null;
44411 var item = this.findItemFromChild(e.getTarget());
44413 this.clearSelections(true);
44416 if (item && (this.multiSelect || this.singleSelect)){
44417 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
44418 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
44419 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
44420 this.unselect(item);
44422 this.select(item, this.multiSelect && e.ctrlKey);
44423 this.lastSelection = item;
44428 onItemClick : function(item, index, e){
44429 if(this.fireEvent("beforeclick", this, index, item, e) === false){
44435 unselect : function(nodeInfo, suppressEvent){
44436 var node = this.getNode(nodeInfo);
44437 if(node && this.isSelected(node)){
44438 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
44439 Roo.fly(node).removeClass(this.selectedClass);
44440 this.selections.remove(node);
44441 if(!suppressEvent){
44442 this.fireEvent("selectionchange", this, this.selections);
44450 * Ext JS Library 1.1.1
44451 * Copyright(c) 2006-2007, Ext JS, LLC.
44453 * Originally Released Under LGPL - original licence link has changed is not relivant.
44456 * <script type="text/javascript">
44460 * @class Roo.LayoutManager
44461 * @extends Roo.util.Observable
44462 * Base class for layout managers.
44464 Roo.LayoutManager = function(container, config){
44465 Roo.LayoutManager.superclass.constructor.call(this);
44466 this.el = Roo.get(container);
44467 // ie scrollbar fix
44468 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
44469 document.body.scroll = "no";
44470 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
44471 this.el.position('relative');
44473 this.id = this.el.id;
44474 this.el.addClass("x-layout-container");
44475 /** false to disable window resize monitoring @type Boolean */
44476 this.monitorWindowResize = true;
44481 * Fires when a layout is performed.
44482 * @param {Roo.LayoutManager} this
44486 * @event regionresized
44487 * Fires when the user resizes a region.
44488 * @param {Roo.LayoutRegion} region The resized region
44489 * @param {Number} newSize The new size (width for east/west, height for north/south)
44491 "regionresized" : true,
44493 * @event regioncollapsed
44494 * Fires when a region is collapsed.
44495 * @param {Roo.LayoutRegion} region The collapsed region
44497 "regioncollapsed" : true,
44499 * @event regionexpanded
44500 * Fires when a region is expanded.
44501 * @param {Roo.LayoutRegion} region The expanded region
44503 "regionexpanded" : true
44505 this.updating = false;
44506 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
44509 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
44511 * Returns true if this layout is currently being updated
44512 * @return {Boolean}
44514 isUpdating : function(){
44515 return this.updating;
44519 * Suspend the LayoutManager from doing auto-layouts while
44520 * making multiple add or remove calls
44522 beginUpdate : function(){
44523 this.updating = true;
44527 * Restore auto-layouts and optionally disable the manager from performing a layout
44528 * @param {Boolean} noLayout true to disable a layout update
44530 endUpdate : function(noLayout){
44531 this.updating = false;
44537 layout: function(){
44541 onRegionResized : function(region, newSize){
44542 this.fireEvent("regionresized", region, newSize);
44546 onRegionCollapsed : function(region){
44547 this.fireEvent("regioncollapsed", region);
44550 onRegionExpanded : function(region){
44551 this.fireEvent("regionexpanded", region);
44555 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
44556 * performs box-model adjustments.
44557 * @return {Object} The size as an object {width: (the width), height: (the height)}
44559 getViewSize : function(){
44561 if(this.el.dom != document.body){
44562 size = this.el.getSize();
44564 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
44566 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
44567 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
44572 * Returns the Element this layout is bound to.
44573 * @return {Roo.Element}
44575 getEl : function(){
44580 * Returns the specified region.
44581 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
44582 * @return {Roo.LayoutRegion}
44584 getRegion : function(target){
44585 return this.regions[target.toLowerCase()];
44588 onWindowResize : function(){
44589 if(this.monitorWindowResize){
44595 * Ext JS Library 1.1.1
44596 * Copyright(c) 2006-2007, Ext JS, LLC.
44598 * Originally Released Under LGPL - original licence link has changed is not relivant.
44601 * <script type="text/javascript">
44604 * @class Roo.BorderLayout
44605 * @extends Roo.LayoutManager
44606 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
44607 * please see: <br><br>
44608 * <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>
44609 * <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>
44612 var layout = new Roo.BorderLayout(document.body, {
44646 preferredTabWidth: 150
44651 var CP = Roo.ContentPanel;
44653 layout.beginUpdate();
44654 layout.add("north", new CP("north", "North"));
44655 layout.add("south", new CP("south", {title: "South", closable: true}));
44656 layout.add("west", new CP("west", {title: "West"}));
44657 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
44658 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
44659 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
44660 layout.getRegion("center").showPanel("center1");
44661 layout.endUpdate();
44664 <b>The container the layout is rendered into can be either the body element or any other element.
44665 If it is not the body element, the container needs to either be an absolute positioned element,
44666 or you will need to add "position:relative" to the css of the container. You will also need to specify
44667 the container size if it is not the body element.</b>
44670 * Create a new BorderLayout
44671 * @param {String/HTMLElement/Element} container The container this layout is bound to
44672 * @param {Object} config Configuration options
44674 Roo.BorderLayout = function(container, config){
44675 config = config || {};
44676 Roo.BorderLayout.superclass.constructor.call(this, container, config);
44677 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
44678 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
44679 var target = this.factory.validRegions[i];
44680 if(config[target]){
44681 this.addRegion(target, config[target]);
44686 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
44688 * Creates and adds a new region if it doesn't already exist.
44689 * @param {String} target The target region key (north, south, east, west or center).
44690 * @param {Object} config The regions config object
44691 * @return {BorderLayoutRegion} The new region
44693 addRegion : function(target, config){
44694 if(!this.regions[target]){
44695 var r = this.factory.create(target, this, config);
44696 this.bindRegion(target, r);
44698 return this.regions[target];
44702 bindRegion : function(name, r){
44703 this.regions[name] = r;
44704 r.on("visibilitychange", this.layout, this);
44705 r.on("paneladded", this.layout, this);
44706 r.on("panelremoved", this.layout, this);
44707 r.on("invalidated", this.layout, this);
44708 r.on("resized", this.onRegionResized, this);
44709 r.on("collapsed", this.onRegionCollapsed, this);
44710 r.on("expanded", this.onRegionExpanded, this);
44714 * Performs a layout update.
44716 layout : function(){
44717 if(this.updating) return;
44718 var size = this.getViewSize();
44719 var w = size.width;
44720 var h = size.height;
44725 //var x = 0, y = 0;
44727 var rs = this.regions;
44728 var north = rs["north"];
44729 var south = rs["south"];
44730 var west = rs["west"];
44731 var east = rs["east"];
44732 var center = rs["center"];
44733 //if(this.hideOnLayout){ // not supported anymore
44734 //c.el.setStyle("display", "none");
44736 if(north && north.isVisible()){
44737 var b = north.getBox();
44738 var m = north.getMargins();
44739 b.width = w - (m.left+m.right);
44742 centerY = b.height + b.y + m.bottom;
44743 centerH -= centerY;
44744 north.updateBox(this.safeBox(b));
44746 if(south && south.isVisible()){
44747 var b = south.getBox();
44748 var m = south.getMargins();
44749 b.width = w - (m.left+m.right);
44751 var totalHeight = (b.height + m.top + m.bottom);
44752 b.y = h - totalHeight + m.top;
44753 centerH -= totalHeight;
44754 south.updateBox(this.safeBox(b));
44756 if(west && west.isVisible()){
44757 var b = west.getBox();
44758 var m = west.getMargins();
44759 b.height = centerH - (m.top+m.bottom);
44761 b.y = centerY + m.top;
44762 var totalWidth = (b.width + m.left + m.right);
44763 centerX += totalWidth;
44764 centerW -= totalWidth;
44765 west.updateBox(this.safeBox(b));
44767 if(east && east.isVisible()){
44768 var b = east.getBox();
44769 var m = east.getMargins();
44770 b.height = centerH - (m.top+m.bottom);
44771 var totalWidth = (b.width + m.left + m.right);
44772 b.x = w - totalWidth + m.left;
44773 b.y = centerY + m.top;
44774 centerW -= totalWidth;
44775 east.updateBox(this.safeBox(b));
44778 var m = center.getMargins();
44780 x: centerX + m.left,
44781 y: centerY + m.top,
44782 width: centerW - (m.left+m.right),
44783 height: centerH - (m.top+m.bottom)
44785 //if(this.hideOnLayout){
44786 //center.el.setStyle("display", "block");
44788 center.updateBox(this.safeBox(centerBox));
44791 this.fireEvent("layout", this);
44795 safeBox : function(box){
44796 box.width = Math.max(0, box.width);
44797 box.height = Math.max(0, box.height);
44802 * Adds a ContentPanel (or subclass) to this layout.
44803 * @param {String} target The target region key (north, south, east, west or center).
44804 * @param {Roo.ContentPanel} panel The panel to add
44805 * @return {Roo.ContentPanel} The added panel
44807 add : function(target, panel){
44809 target = target.toLowerCase();
44810 return this.regions[target].add(panel);
44814 * Remove a ContentPanel (or subclass) to this layout.
44815 * @param {String} target The target region key (north, south, east, west or center).
44816 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
44817 * @return {Roo.ContentPanel} The removed panel
44819 remove : function(target, panel){
44820 target = target.toLowerCase();
44821 return this.regions[target].remove(panel);
44825 * Searches all regions for a panel with the specified id
44826 * @param {String} panelId
44827 * @return {Roo.ContentPanel} The panel or null if it wasn't found
44829 findPanel : function(panelId){
44830 var rs = this.regions;
44831 for(var target in rs){
44832 if(typeof rs[target] != "function"){
44833 var p = rs[target].getPanel(panelId);
44843 * Searches all regions for a panel with the specified id and activates (shows) it.
44844 * @param {String/ContentPanel} panelId The panels id or the panel itself
44845 * @return {Roo.ContentPanel} The shown panel or null
44847 showPanel : function(panelId) {
44848 var rs = this.regions;
44849 for(var target in rs){
44850 var r = rs[target];
44851 if(typeof r != "function"){
44852 if(r.hasPanel(panelId)){
44853 return r.showPanel(panelId);
44861 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
44862 * @param {Roo.state.Provider} provider (optional) An alternate state provider
44864 restoreState : function(provider){
44866 provider = Roo.state.Manager;
44868 var sm = new Roo.LayoutStateManager();
44869 sm.init(this, provider);
44873 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
44874 * object should contain properties for each region to add ContentPanels to, and each property's value should be
44875 * a valid ContentPanel config object. Example:
44877 // Create the main layout
44878 var layout = new Roo.BorderLayout('main-ct', {
44889 // Create and add multiple ContentPanels at once via configs
44892 id: 'source-files',
44894 title:'Ext Source Files',
44907 * @param {Object} regions An object containing ContentPanel configs by region name
44909 batchAdd : function(regions){
44910 this.beginUpdate();
44911 for(var rname in regions){
44912 var lr = this.regions[rname];
44914 this.addTypedPanels(lr, regions[rname]);
44921 addTypedPanels : function(lr, ps){
44922 if(typeof ps == 'string'){
44923 lr.add(new Roo.ContentPanel(ps));
44925 else if(ps instanceof Array){
44926 for(var i =0, len = ps.length; i < len; i++){
44927 this.addTypedPanels(lr, ps[i]);
44930 else if(!ps.events){ // raw config?
44932 delete ps.el; // prevent conflict
44933 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
44935 else { // panel object assumed!
44940 * Adds a xtype elements to the layout.
44944 xtype : 'ContentPanel',
44951 xtype : 'NestedLayoutPanel',
44957 items : [ ... list of content panels or nested layout panels.. ]
44961 * @param {Object} cfg Xtype definition of item to add.
44963 addxtype : function(cfg)
44965 // basically accepts a pannel...
44966 // can accept a layout region..!?!?
44967 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
44969 if (!cfg.xtype.match(/Panel$/)) {
44974 if (typeof(cfg.region) == 'undefined') {
44975 Roo.log("Failed to add Panel, region was not set");
44979 var region = cfg.region;
44985 xitems = cfg.items;
44992 case 'ContentPanel': // ContentPanel (el, cfg)
44993 case 'ScrollPanel': // ContentPanel (el, cfg)
44994 if(cfg.autoCreate) {
44995 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44997 var el = this.el.createChild();
44998 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
45001 this.add(region, ret);
45005 case 'TreePanel': // our new panel!
45006 cfg.el = this.el.createChild();
45007 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
45008 this.add(region, ret);
45011 case 'NestedLayoutPanel':
45012 // create a new Layout (which is a Border Layout...
45013 var el = this.el.createChild();
45014 var clayout = cfg.layout;
45016 clayout.items = clayout.items || [];
45017 // replace this exitems with the clayout ones..
45018 xitems = clayout.items;
45021 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
45022 cfg.background = false;
45024 var layout = new Roo.BorderLayout(el, clayout);
45026 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
45027 //console.log('adding nested layout panel ' + cfg.toSource());
45028 this.add(region, ret);
45029 nb = {}; /// find first...
45034 // needs grid and region
45036 //var el = this.getRegion(region).el.createChild();
45037 var el = this.el.createChild();
45038 // create the grid first...
45040 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
45042 if (region == 'center' && this.active ) {
45043 cfg.background = false;
45045 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
45047 this.add(region, ret);
45048 if (cfg.background) {
45049 ret.on('activate', function(gp) {
45050 if (!gp.grid.rendered) {
45063 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
45065 // GridPanel (grid, cfg)
45068 this.beginUpdate();
45072 Roo.each(xitems, function(i) {
45073 region = nb && i.region ? i.region : false;
45075 var add = ret.addxtype(i);
45078 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
45079 if (!i.background) {
45080 abn[region] = nb[region] ;
45087 // make the last non-background panel active..
45088 //if (nb) { Roo.log(abn); }
45091 for(var r in abn) {
45092 region = this.getRegion(r);
45094 // tried using nb[r], but it does not work..
45096 region.showPanel(abn[r]);
45107 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
45108 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
45109 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
45110 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
45113 var CP = Roo.ContentPanel;
45115 var layout = Roo.BorderLayout.create({
45119 panels: [new CP("north", "North")]
45128 panels: [new CP("west", {title: "West"})]
45137 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
45146 panels: [new CP("south", {title: "South", closable: true})]
45153 preferredTabWidth: 150,
45155 new CP("center1", {title: "Close Me", closable: true}),
45156 new CP("center2", {title: "Center Panel", closable: false})
45161 layout.getRegion("center").showPanel("center1");
45166 Roo.BorderLayout.create = function(config, targetEl){
45167 var layout = new Roo.BorderLayout(targetEl || document.body, config);
45168 layout.beginUpdate();
45169 var regions = Roo.BorderLayout.RegionFactory.validRegions;
45170 for(var j = 0, jlen = regions.length; j < jlen; j++){
45171 var lr = regions[j];
45172 if(layout.regions[lr] && config[lr].panels){
45173 var r = layout.regions[lr];
45174 var ps = config[lr].panels;
45175 layout.addTypedPanels(r, ps);
45178 layout.endUpdate();
45183 Roo.BorderLayout.RegionFactory = {
45185 validRegions : ["north","south","east","west","center"],
45188 create : function(target, mgr, config){
45189 target = target.toLowerCase();
45190 if(config.lightweight || config.basic){
45191 return new Roo.BasicLayoutRegion(mgr, config, target);
45195 return new Roo.NorthLayoutRegion(mgr, config);
45197 return new Roo.SouthLayoutRegion(mgr, config);
45199 return new Roo.EastLayoutRegion(mgr, config);
45201 return new Roo.WestLayoutRegion(mgr, config);
45203 return new Roo.CenterLayoutRegion(mgr, config);
45205 throw 'Layout region "'+target+'" not supported.';
45209 * Ext JS Library 1.1.1
45210 * Copyright(c) 2006-2007, Ext JS, LLC.
45212 * Originally Released Under LGPL - original licence link has changed is not relivant.
45215 * <script type="text/javascript">
45219 * @class Roo.BasicLayoutRegion
45220 * @extends Roo.util.Observable
45221 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
45222 * and does not have a titlebar, tabs or any other features. All it does is size and position
45223 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
45225 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
45227 this.position = pos;
45230 * @scope Roo.BasicLayoutRegion
45234 * @event beforeremove
45235 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
45236 * @param {Roo.LayoutRegion} this
45237 * @param {Roo.ContentPanel} panel The panel
45238 * @param {Object} e The cancel event object
45240 "beforeremove" : true,
45242 * @event invalidated
45243 * Fires when the layout for this region is changed.
45244 * @param {Roo.LayoutRegion} this
45246 "invalidated" : true,
45248 * @event visibilitychange
45249 * Fires when this region is shown or hidden
45250 * @param {Roo.LayoutRegion} this
45251 * @param {Boolean} visibility true or false
45253 "visibilitychange" : true,
45255 * @event paneladded
45256 * Fires when a panel is added.
45257 * @param {Roo.LayoutRegion} this
45258 * @param {Roo.ContentPanel} panel The panel
45260 "paneladded" : true,
45262 * @event panelremoved
45263 * Fires when a panel is removed.
45264 * @param {Roo.LayoutRegion} this
45265 * @param {Roo.ContentPanel} panel The panel
45267 "panelremoved" : true,
45270 * Fires when this region is collapsed.
45271 * @param {Roo.LayoutRegion} this
45273 "collapsed" : true,
45276 * Fires when this region is expanded.
45277 * @param {Roo.LayoutRegion} this
45282 * Fires when this region is slid into view.
45283 * @param {Roo.LayoutRegion} this
45285 "slideshow" : true,
45288 * Fires when this region slides out of view.
45289 * @param {Roo.LayoutRegion} this
45291 "slidehide" : true,
45293 * @event panelactivated
45294 * Fires when a panel is activated.
45295 * @param {Roo.LayoutRegion} this
45296 * @param {Roo.ContentPanel} panel The activated panel
45298 "panelactivated" : true,
45301 * Fires when the user resizes this region.
45302 * @param {Roo.LayoutRegion} this
45303 * @param {Number} newSize The new size (width for east/west, height for north/south)
45307 /** A collection of panels in this region. @type Roo.util.MixedCollection */
45308 this.panels = new Roo.util.MixedCollection();
45309 this.panels.getKey = this.getPanelId.createDelegate(this);
45311 this.activePanel = null;
45312 // ensure listeners are added...
45314 if (config.listeners || config.events) {
45315 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
45316 listeners : config.listeners || {},
45317 events : config.events || {}
45321 if(skipConfig !== true){
45322 this.applyConfig(config);
45326 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
45327 getPanelId : function(p){
45331 applyConfig : function(config){
45332 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45333 this.config = config;
45338 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
45339 * the width, for horizontal (north, south) the height.
45340 * @param {Number} newSize The new width or height
45342 resizeTo : function(newSize){
45343 var el = this.el ? this.el :
45344 (this.activePanel ? this.activePanel.getEl() : null);
45346 switch(this.position){
45349 el.setWidth(newSize);
45350 this.fireEvent("resized", this, newSize);
45354 el.setHeight(newSize);
45355 this.fireEvent("resized", this, newSize);
45361 getBox : function(){
45362 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
45365 getMargins : function(){
45366 return this.margins;
45369 updateBox : function(box){
45371 var el = this.activePanel.getEl();
45372 el.dom.style.left = box.x + "px";
45373 el.dom.style.top = box.y + "px";
45374 this.activePanel.setSize(box.width, box.height);
45378 * Returns the container element for this region.
45379 * @return {Roo.Element}
45381 getEl : function(){
45382 return this.activePanel;
45386 * Returns true if this region is currently visible.
45387 * @return {Boolean}
45389 isVisible : function(){
45390 return this.activePanel ? true : false;
45393 setActivePanel : function(panel){
45394 panel = this.getPanel(panel);
45395 if(this.activePanel && this.activePanel != panel){
45396 this.activePanel.setActiveState(false);
45397 this.activePanel.getEl().setLeftTop(-10000,-10000);
45399 this.activePanel = panel;
45400 panel.setActiveState(true);
45402 panel.setSize(this.box.width, this.box.height);
45404 this.fireEvent("panelactivated", this, panel);
45405 this.fireEvent("invalidated");
45409 * Show the specified panel.
45410 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
45411 * @return {Roo.ContentPanel} The shown panel or null
45413 showPanel : function(panel){
45414 if(panel = this.getPanel(panel)){
45415 this.setActivePanel(panel);
45421 * Get the active panel for this region.
45422 * @return {Roo.ContentPanel} The active panel or null
45424 getActivePanel : function(){
45425 return this.activePanel;
45429 * Add the passed ContentPanel(s)
45430 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45431 * @return {Roo.ContentPanel} The panel added (if only one was added)
45433 add : function(panel){
45434 if(arguments.length > 1){
45435 for(var i = 0, len = arguments.length; i < len; i++) {
45436 this.add(arguments[i]);
45440 if(this.hasPanel(panel)){
45441 this.showPanel(panel);
45444 var el = panel.getEl();
45445 if(el.dom.parentNode != this.mgr.el.dom){
45446 this.mgr.el.dom.appendChild(el.dom);
45448 if(panel.setRegion){
45449 panel.setRegion(this);
45451 this.panels.add(panel);
45452 el.setStyle("position", "absolute");
45453 if(!panel.background){
45454 this.setActivePanel(panel);
45455 if(this.config.initialSize && this.panels.getCount()==1){
45456 this.resizeTo(this.config.initialSize);
45459 this.fireEvent("paneladded", this, panel);
45464 * Returns true if the panel is in this region.
45465 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45466 * @return {Boolean}
45468 hasPanel : function(panel){
45469 if(typeof panel == "object"){ // must be panel obj
45470 panel = panel.getId();
45472 return this.getPanel(panel) ? true : false;
45476 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45477 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45478 * @param {Boolean} preservePanel Overrides the config preservePanel option
45479 * @return {Roo.ContentPanel} The panel that was removed
45481 remove : function(panel, preservePanel){
45482 panel = this.getPanel(panel);
45487 this.fireEvent("beforeremove", this, panel, e);
45488 if(e.cancel === true){
45491 var panelId = panel.getId();
45492 this.panels.removeKey(panelId);
45497 * Returns the panel specified or null if it's not in this region.
45498 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45499 * @return {Roo.ContentPanel}
45501 getPanel : function(id){
45502 if(typeof id == "object"){ // must be panel obj
45505 return this.panels.get(id);
45509 * Returns this regions position (north/south/east/west/center).
45512 getPosition: function(){
45513 return this.position;
45517 * Ext JS Library 1.1.1
45518 * Copyright(c) 2006-2007, Ext JS, LLC.
45520 * Originally Released Under LGPL - original licence link has changed is not relivant.
45523 * <script type="text/javascript">
45527 * @class Roo.LayoutRegion
45528 * @extends Roo.BasicLayoutRegion
45529 * This class represents a region in a layout manager.
45530 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
45531 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
45532 * @cfg {Boolean} floatable False to disable floating (defaults to true)
45533 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
45534 * @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})
45535 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
45536 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
45537 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
45538 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
45539 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
45540 * @cfg {String} title The title for the region (overrides panel titles)
45541 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
45542 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
45543 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
45544 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
45545 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
45546 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
45547 * the space available, similar to FireFox 1.5 tabs (defaults to false)
45548 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
45549 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
45550 * @cfg {Boolean} showPin True to show a pin button
45551 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
45552 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
45553 * @cfg {Boolean} disableTabTips True to disable tab tooltips
45554 * @cfg {Number} width For East/West panels
45555 * @cfg {Number} height For North/South panels
45556 * @cfg {Boolean} split To show the splitter
45557 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
45559 Roo.LayoutRegion = function(mgr, config, pos){
45560 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
45561 var dh = Roo.DomHelper;
45562 /** This region's container element
45563 * @type Roo.Element */
45564 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
45565 /** This region's title element
45566 * @type Roo.Element */
45568 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
45569 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
45570 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
45572 this.titleEl.enableDisplayMode();
45573 /** This region's title text element
45574 * @type HTMLElement */
45575 this.titleTextEl = this.titleEl.dom.firstChild;
45576 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
45577 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
45578 this.closeBtn.enableDisplayMode();
45579 this.closeBtn.on("click", this.closeClicked, this);
45580 this.closeBtn.hide();
45582 this.createBody(config);
45583 this.visible = true;
45584 this.collapsed = false;
45586 if(config.hideWhenEmpty){
45588 this.on("paneladded", this.validateVisibility, this);
45589 this.on("panelremoved", this.validateVisibility, this);
45591 this.applyConfig(config);
45594 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
45596 createBody : function(){
45597 /** This region's body element
45598 * @type Roo.Element */
45599 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
45602 applyConfig : function(c){
45603 if(c.collapsible && this.position != "center" && !this.collapsedEl){
45604 var dh = Roo.DomHelper;
45605 if(c.titlebar !== false){
45606 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
45607 this.collapseBtn.on("click", this.collapse, this);
45608 this.collapseBtn.enableDisplayMode();
45610 if(c.showPin === true || this.showPin){
45611 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
45612 this.stickBtn.enableDisplayMode();
45613 this.stickBtn.on("click", this.expand, this);
45614 this.stickBtn.hide();
45617 /** This region's collapsed element
45618 * @type Roo.Element */
45619 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
45620 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
45622 if(c.floatable !== false){
45623 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
45624 this.collapsedEl.on("click", this.collapseClick, this);
45627 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
45628 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
45629 id: "message", unselectable: "on", style:{"float":"left"}});
45630 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
45632 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
45633 this.expandBtn.on("click", this.expand, this);
45635 if(this.collapseBtn){
45636 this.collapseBtn.setVisible(c.collapsible == true);
45638 this.cmargins = c.cmargins || this.cmargins ||
45639 (this.position == "west" || this.position == "east" ?
45640 {top: 0, left: 2, right:2, bottom: 0} :
45641 {top: 2, left: 0, right:0, bottom: 2});
45642 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45643 this.bottomTabs = c.tabPosition != "top";
45644 this.autoScroll = c.autoScroll || false;
45645 if(this.autoScroll){
45646 this.bodyEl.setStyle("overflow", "auto");
45648 this.bodyEl.setStyle("overflow", "hidden");
45650 //if(c.titlebar !== false){
45651 if((!c.titlebar && !c.title) || c.titlebar === false){
45652 this.titleEl.hide();
45654 this.titleEl.show();
45656 this.titleTextEl.innerHTML = c.title;
45660 this.duration = c.duration || .30;
45661 this.slideDuration = c.slideDuration || .45;
45664 this.collapse(true);
45671 * Returns true if this region is currently visible.
45672 * @return {Boolean}
45674 isVisible : function(){
45675 return this.visible;
45679 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
45680 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
45682 setCollapsedTitle : function(title){
45683 title = title || " ";
45684 if(this.collapsedTitleTextEl){
45685 this.collapsedTitleTextEl.innerHTML = title;
45689 getBox : function(){
45691 if(!this.collapsed){
45692 b = this.el.getBox(false, true);
45694 b = this.collapsedEl.getBox(false, true);
45699 getMargins : function(){
45700 return this.collapsed ? this.cmargins : this.margins;
45703 highlight : function(){
45704 this.el.addClass("x-layout-panel-dragover");
45707 unhighlight : function(){
45708 this.el.removeClass("x-layout-panel-dragover");
45711 updateBox : function(box){
45713 if(!this.collapsed){
45714 this.el.dom.style.left = box.x + "px";
45715 this.el.dom.style.top = box.y + "px";
45716 this.updateBody(box.width, box.height);
45718 this.collapsedEl.dom.style.left = box.x + "px";
45719 this.collapsedEl.dom.style.top = box.y + "px";
45720 this.collapsedEl.setSize(box.width, box.height);
45723 this.tabs.autoSizeTabs();
45727 updateBody : function(w, h){
45729 this.el.setWidth(w);
45730 w -= this.el.getBorderWidth("rl");
45731 if(this.config.adjustments){
45732 w += this.config.adjustments[0];
45736 this.el.setHeight(h);
45737 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
45738 h -= this.el.getBorderWidth("tb");
45739 if(this.config.adjustments){
45740 h += this.config.adjustments[1];
45742 this.bodyEl.setHeight(h);
45744 h = this.tabs.syncHeight(h);
45747 if(this.panelSize){
45748 w = w !== null ? w : this.panelSize.width;
45749 h = h !== null ? h : this.panelSize.height;
45751 if(this.activePanel){
45752 var el = this.activePanel.getEl();
45753 w = w !== null ? w : el.getWidth();
45754 h = h !== null ? h : el.getHeight();
45755 this.panelSize = {width: w, height: h};
45756 this.activePanel.setSize(w, h);
45758 if(Roo.isIE && this.tabs){
45759 this.tabs.el.repaint();
45764 * Returns the container element for this region.
45765 * @return {Roo.Element}
45767 getEl : function(){
45772 * Hides this region.
45775 if(!this.collapsed){
45776 this.el.dom.style.left = "-2000px";
45779 this.collapsedEl.dom.style.left = "-2000px";
45780 this.collapsedEl.hide();
45782 this.visible = false;
45783 this.fireEvent("visibilitychange", this, false);
45787 * Shows this region if it was previously hidden.
45790 if(!this.collapsed){
45793 this.collapsedEl.show();
45795 this.visible = true;
45796 this.fireEvent("visibilitychange", this, true);
45799 closeClicked : function(){
45800 if(this.activePanel){
45801 this.remove(this.activePanel);
45805 collapseClick : function(e){
45807 e.stopPropagation();
45810 e.stopPropagation();
45816 * Collapses this region.
45817 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
45819 collapse : function(skipAnim){
45820 if(this.collapsed) return;
45821 this.collapsed = true;
45823 this.split.el.hide();
45825 if(this.config.animate && skipAnim !== true){
45826 this.fireEvent("invalidated", this);
45827 this.animateCollapse();
45829 this.el.setLocation(-20000,-20000);
45831 this.collapsedEl.show();
45832 this.fireEvent("collapsed", this);
45833 this.fireEvent("invalidated", this);
45837 animateCollapse : function(){
45842 * Expands this region if it was previously collapsed.
45843 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
45844 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
45846 expand : function(e, skipAnim){
45847 if(e) e.stopPropagation();
45848 if(!this.collapsed || this.el.hasActiveFx()) return;
45850 this.afterSlideIn();
45853 this.collapsed = false;
45854 if(this.config.animate && skipAnim !== true){
45855 this.animateExpand();
45859 this.split.el.show();
45861 this.collapsedEl.setLocation(-2000,-2000);
45862 this.collapsedEl.hide();
45863 this.fireEvent("invalidated", this);
45864 this.fireEvent("expanded", this);
45868 animateExpand : function(){
45872 initTabs : function()
45874 this.bodyEl.setStyle("overflow", "hidden");
45875 var ts = new Roo.TabPanel(
45878 tabPosition: this.bottomTabs ? 'bottom' : 'top',
45879 disableTooltips: this.config.disableTabTips,
45880 toolbar : this.config.toolbar
45883 if(this.config.hideTabs){
45884 ts.stripWrap.setDisplayed(false);
45887 ts.resizeTabs = this.config.resizeTabs === true;
45888 ts.minTabWidth = this.config.minTabWidth || 40;
45889 ts.maxTabWidth = this.config.maxTabWidth || 250;
45890 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
45891 ts.monitorResize = false;
45892 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
45893 ts.bodyEl.addClass('x-layout-tabs-body');
45894 this.panels.each(this.initPanelAsTab, this);
45897 initPanelAsTab : function(panel){
45898 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
45899 this.config.closeOnTab && panel.isClosable());
45900 if(panel.tabTip !== undefined){
45901 ti.setTooltip(panel.tabTip);
45903 ti.on("activate", function(){
45904 this.setActivePanel(panel);
45906 if(this.config.closeOnTab){
45907 ti.on("beforeclose", function(t, e){
45909 this.remove(panel);
45915 updatePanelTitle : function(panel, title){
45916 if(this.activePanel == panel){
45917 this.updateTitle(title);
45920 var ti = this.tabs.getTab(panel.getEl().id);
45922 if(panel.tabTip !== undefined){
45923 ti.setTooltip(panel.tabTip);
45928 updateTitle : function(title){
45929 if(this.titleTextEl && !this.config.title){
45930 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
45934 setActivePanel : function(panel){
45935 panel = this.getPanel(panel);
45936 if(this.activePanel && this.activePanel != panel){
45937 this.activePanel.setActiveState(false);
45939 this.activePanel = panel;
45940 panel.setActiveState(true);
45941 if(this.panelSize){
45942 panel.setSize(this.panelSize.width, this.panelSize.height);
45945 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
45947 this.updateTitle(panel.getTitle());
45949 this.fireEvent("invalidated", this);
45951 this.fireEvent("panelactivated", this, panel);
45955 * Shows the specified panel.
45956 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
45957 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
45959 showPanel : function(panel){
45960 if(panel = this.getPanel(panel)){
45962 var tab = this.tabs.getTab(panel.getEl().id);
45963 if(tab.isHidden()){
45964 this.tabs.unhideTab(tab.id);
45968 this.setActivePanel(panel);
45975 * Get the active panel for this region.
45976 * @return {Roo.ContentPanel} The active panel or null
45978 getActivePanel : function(){
45979 return this.activePanel;
45982 validateVisibility : function(){
45983 if(this.panels.getCount() < 1){
45984 this.updateTitle(" ");
45985 this.closeBtn.hide();
45988 if(!this.isVisible()){
45995 * Adds the passed ContentPanel(s) to this region.
45996 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45997 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
45999 add : function(panel){
46000 if(arguments.length > 1){
46001 for(var i = 0, len = arguments.length; i < len; i++) {
46002 this.add(arguments[i]);
46006 if(this.hasPanel(panel)){
46007 this.showPanel(panel);
46010 panel.setRegion(this);
46011 this.panels.add(panel);
46012 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
46013 this.bodyEl.dom.appendChild(panel.getEl().dom);
46014 if(panel.background !== true){
46015 this.setActivePanel(panel);
46017 this.fireEvent("paneladded", this, panel);
46023 this.initPanelAsTab(panel);
46025 if(panel.background !== true){
46026 this.tabs.activate(panel.getEl().id);
46028 this.fireEvent("paneladded", this, panel);
46033 * Hides the tab for the specified panel.
46034 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46036 hidePanel : function(panel){
46037 if(this.tabs && (panel = this.getPanel(panel))){
46038 this.tabs.hideTab(panel.getEl().id);
46043 * Unhides the tab for a previously hidden panel.
46044 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46046 unhidePanel : function(panel){
46047 if(this.tabs && (panel = this.getPanel(panel))){
46048 this.tabs.unhideTab(panel.getEl().id);
46052 clearPanels : function(){
46053 while(this.panels.getCount() > 0){
46054 this.remove(this.panels.first());
46059 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
46060 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46061 * @param {Boolean} preservePanel Overrides the config preservePanel option
46062 * @return {Roo.ContentPanel} The panel that was removed
46064 remove : function(panel, preservePanel){
46065 panel = this.getPanel(panel);
46070 this.fireEvent("beforeremove", this, panel, e);
46071 if(e.cancel === true){
46074 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
46075 var panelId = panel.getId();
46076 this.panels.removeKey(panelId);
46078 document.body.appendChild(panel.getEl().dom);
46081 this.tabs.removeTab(panel.getEl().id);
46082 }else if (!preservePanel){
46083 this.bodyEl.dom.removeChild(panel.getEl().dom);
46085 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
46086 var p = this.panels.first();
46087 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
46088 tempEl.appendChild(p.getEl().dom);
46089 this.bodyEl.update("");
46090 this.bodyEl.dom.appendChild(p.getEl().dom);
46092 this.updateTitle(p.getTitle());
46094 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
46095 this.setActivePanel(p);
46097 panel.setRegion(null);
46098 if(this.activePanel == panel){
46099 this.activePanel = null;
46101 if(this.config.autoDestroy !== false && preservePanel !== true){
46102 try{panel.destroy();}catch(e){}
46104 this.fireEvent("panelremoved", this, panel);
46109 * Returns the TabPanel component used by this region
46110 * @return {Roo.TabPanel}
46112 getTabs : function(){
46116 createTool : function(parentEl, className){
46117 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
46118 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
46119 btn.addClassOnOver("x-layout-tools-button-over");
46124 * Ext JS Library 1.1.1
46125 * Copyright(c) 2006-2007, Ext JS, LLC.
46127 * Originally Released Under LGPL - original licence link has changed is not relivant.
46130 * <script type="text/javascript">
46136 * @class Roo.SplitLayoutRegion
46137 * @extends Roo.LayoutRegion
46138 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
46140 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
46141 this.cursor = cursor;
46142 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
46145 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
46146 splitTip : "Drag to resize.",
46147 collapsibleSplitTip : "Drag to resize. Double click to hide.",
46148 useSplitTips : false,
46150 applyConfig : function(config){
46151 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
46154 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
46155 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
46156 /** The SplitBar for this region
46157 * @type Roo.SplitBar */
46158 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
46159 this.split.on("moved", this.onSplitMove, this);
46160 this.split.useShim = config.useShim === true;
46161 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
46162 if(this.useSplitTips){
46163 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
46165 if(config.collapsible){
46166 this.split.el.on("dblclick", this.collapse, this);
46169 if(typeof config.minSize != "undefined"){
46170 this.split.minSize = config.minSize;
46172 if(typeof config.maxSize != "undefined"){
46173 this.split.maxSize = config.maxSize;
46175 if(config.hideWhenEmpty || config.hidden || config.collapsed){
46176 this.hideSplitter();
46181 getHMaxSize : function(){
46182 var cmax = this.config.maxSize || 10000;
46183 var center = this.mgr.getRegion("center");
46184 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
46187 getVMaxSize : function(){
46188 var cmax = this.config.maxSize || 10000;
46189 var center = this.mgr.getRegion("center");
46190 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
46193 onSplitMove : function(split, newSize){
46194 this.fireEvent("resized", this, newSize);
46198 * Returns the {@link Roo.SplitBar} for this region.
46199 * @return {Roo.SplitBar}
46201 getSplitBar : function(){
46206 this.hideSplitter();
46207 Roo.SplitLayoutRegion.superclass.hide.call(this);
46210 hideSplitter : function(){
46212 this.split.el.setLocation(-2000,-2000);
46213 this.split.el.hide();
46219 this.split.el.show();
46221 Roo.SplitLayoutRegion.superclass.show.call(this);
46224 beforeSlide: function(){
46225 if(Roo.isGecko){// firefox overflow auto bug workaround
46226 this.bodyEl.clip();
46227 if(this.tabs) this.tabs.bodyEl.clip();
46228 if(this.activePanel){
46229 this.activePanel.getEl().clip();
46231 if(this.activePanel.beforeSlide){
46232 this.activePanel.beforeSlide();
46238 afterSlide : function(){
46239 if(Roo.isGecko){// firefox overflow auto bug workaround
46240 this.bodyEl.unclip();
46241 if(this.tabs) this.tabs.bodyEl.unclip();
46242 if(this.activePanel){
46243 this.activePanel.getEl().unclip();
46244 if(this.activePanel.afterSlide){
46245 this.activePanel.afterSlide();
46251 initAutoHide : function(){
46252 if(this.autoHide !== false){
46253 if(!this.autoHideHd){
46254 var st = new Roo.util.DelayedTask(this.slideIn, this);
46255 this.autoHideHd = {
46256 "mouseout": function(e){
46257 if(!e.within(this.el, true)){
46261 "mouseover" : function(e){
46267 this.el.on(this.autoHideHd);
46271 clearAutoHide : function(){
46272 if(this.autoHide !== false){
46273 this.el.un("mouseout", this.autoHideHd.mouseout);
46274 this.el.un("mouseover", this.autoHideHd.mouseover);
46278 clearMonitor : function(){
46279 Roo.get(document).un("click", this.slideInIf, this);
46282 // these names are backwards but not changed for compat
46283 slideOut : function(){
46284 if(this.isSlid || this.el.hasActiveFx()){
46287 this.isSlid = true;
46288 if(this.collapseBtn){
46289 this.collapseBtn.hide();
46291 this.closeBtnState = this.closeBtn.getStyle('display');
46292 this.closeBtn.hide();
46294 this.stickBtn.show();
46297 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
46298 this.beforeSlide();
46299 this.el.setStyle("z-index", 10001);
46300 this.el.slideIn(this.getSlideAnchor(), {
46301 callback: function(){
46303 this.initAutoHide();
46304 Roo.get(document).on("click", this.slideInIf, this);
46305 this.fireEvent("slideshow", this);
46312 afterSlideIn : function(){
46313 this.clearAutoHide();
46314 this.isSlid = false;
46315 this.clearMonitor();
46316 this.el.setStyle("z-index", "");
46317 if(this.collapseBtn){
46318 this.collapseBtn.show();
46320 this.closeBtn.setStyle('display', this.closeBtnState);
46322 this.stickBtn.hide();
46324 this.fireEvent("slidehide", this);
46327 slideIn : function(cb){
46328 if(!this.isSlid || this.el.hasActiveFx()){
46332 this.isSlid = false;
46333 this.beforeSlide();
46334 this.el.slideOut(this.getSlideAnchor(), {
46335 callback: function(){
46336 this.el.setLeftTop(-10000, -10000);
46338 this.afterSlideIn();
46346 slideInIf : function(e){
46347 if(!e.within(this.el)){
46352 animateCollapse : function(){
46353 this.beforeSlide();
46354 this.el.setStyle("z-index", 20000);
46355 var anchor = this.getSlideAnchor();
46356 this.el.slideOut(anchor, {
46357 callback : function(){
46358 this.el.setStyle("z-index", "");
46359 this.collapsedEl.slideIn(anchor, {duration:.3});
46361 this.el.setLocation(-10000,-10000);
46363 this.fireEvent("collapsed", this);
46370 animateExpand : function(){
46371 this.beforeSlide();
46372 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
46373 this.el.setStyle("z-index", 20000);
46374 this.collapsedEl.hide({
46377 this.el.slideIn(this.getSlideAnchor(), {
46378 callback : function(){
46379 this.el.setStyle("z-index", "");
46382 this.split.el.show();
46384 this.fireEvent("invalidated", this);
46385 this.fireEvent("expanded", this);
46413 getAnchor : function(){
46414 return this.anchors[this.position];
46417 getCollapseAnchor : function(){
46418 return this.canchors[this.position];
46421 getSlideAnchor : function(){
46422 return this.sanchors[this.position];
46425 getAlignAdj : function(){
46426 var cm = this.cmargins;
46427 switch(this.position){
46443 getExpandAdj : function(){
46444 var c = this.collapsedEl, cm = this.cmargins;
46445 switch(this.position){
46447 return [-(cm.right+c.getWidth()+cm.left), 0];
46450 return [cm.right+c.getWidth()+cm.left, 0];
46453 return [0, -(cm.top+cm.bottom+c.getHeight())];
46456 return [0, cm.top+cm.bottom+c.getHeight()];
46462 * Ext JS Library 1.1.1
46463 * Copyright(c) 2006-2007, Ext JS, LLC.
46465 * Originally Released Under LGPL - original licence link has changed is not relivant.
46468 * <script type="text/javascript">
46471 * These classes are private internal classes
46473 Roo.CenterLayoutRegion = function(mgr, config){
46474 Roo.LayoutRegion.call(this, mgr, config, "center");
46475 this.visible = true;
46476 this.minWidth = config.minWidth || 20;
46477 this.minHeight = config.minHeight || 20;
46480 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
46482 // center panel can't be hidden
46486 // center panel can't be hidden
46489 getMinWidth: function(){
46490 return this.minWidth;
46493 getMinHeight: function(){
46494 return this.minHeight;
46499 Roo.NorthLayoutRegion = function(mgr, config){
46500 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
46502 this.split.placement = Roo.SplitBar.TOP;
46503 this.split.orientation = Roo.SplitBar.VERTICAL;
46504 this.split.el.addClass("x-layout-split-v");
46506 var size = config.initialSize || config.height;
46507 if(typeof size != "undefined"){
46508 this.el.setHeight(size);
46511 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
46512 orientation: Roo.SplitBar.VERTICAL,
46513 getBox : function(){
46514 if(this.collapsed){
46515 return this.collapsedEl.getBox();
46517 var box = this.el.getBox();
46519 box.height += this.split.el.getHeight();
46524 updateBox : function(box){
46525 if(this.split && !this.collapsed){
46526 box.height -= this.split.el.getHeight();
46527 this.split.el.setLeft(box.x);
46528 this.split.el.setTop(box.y+box.height);
46529 this.split.el.setWidth(box.width);
46531 if(this.collapsed){
46532 this.updateBody(box.width, null);
46534 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46538 Roo.SouthLayoutRegion = function(mgr, config){
46539 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
46541 this.split.placement = Roo.SplitBar.BOTTOM;
46542 this.split.orientation = Roo.SplitBar.VERTICAL;
46543 this.split.el.addClass("x-layout-split-v");
46545 var size = config.initialSize || config.height;
46546 if(typeof size != "undefined"){
46547 this.el.setHeight(size);
46550 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
46551 orientation: Roo.SplitBar.VERTICAL,
46552 getBox : function(){
46553 if(this.collapsed){
46554 return this.collapsedEl.getBox();
46556 var box = this.el.getBox();
46558 var sh = this.split.el.getHeight();
46565 updateBox : function(box){
46566 if(this.split && !this.collapsed){
46567 var sh = this.split.el.getHeight();
46570 this.split.el.setLeft(box.x);
46571 this.split.el.setTop(box.y-sh);
46572 this.split.el.setWidth(box.width);
46574 if(this.collapsed){
46575 this.updateBody(box.width, null);
46577 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46581 Roo.EastLayoutRegion = function(mgr, config){
46582 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
46584 this.split.placement = Roo.SplitBar.RIGHT;
46585 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46586 this.split.el.addClass("x-layout-split-h");
46588 var size = config.initialSize || config.width;
46589 if(typeof size != "undefined"){
46590 this.el.setWidth(size);
46593 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
46594 orientation: Roo.SplitBar.HORIZONTAL,
46595 getBox : function(){
46596 if(this.collapsed){
46597 return this.collapsedEl.getBox();
46599 var box = this.el.getBox();
46601 var sw = this.split.el.getWidth();
46608 updateBox : function(box){
46609 if(this.split && !this.collapsed){
46610 var sw = this.split.el.getWidth();
46612 this.split.el.setLeft(box.x);
46613 this.split.el.setTop(box.y);
46614 this.split.el.setHeight(box.height);
46617 if(this.collapsed){
46618 this.updateBody(null, box.height);
46620 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46624 Roo.WestLayoutRegion = function(mgr, config){
46625 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
46627 this.split.placement = Roo.SplitBar.LEFT;
46628 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46629 this.split.el.addClass("x-layout-split-h");
46631 var size = config.initialSize || config.width;
46632 if(typeof size != "undefined"){
46633 this.el.setWidth(size);
46636 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
46637 orientation: Roo.SplitBar.HORIZONTAL,
46638 getBox : function(){
46639 if(this.collapsed){
46640 return this.collapsedEl.getBox();
46642 var box = this.el.getBox();
46644 box.width += this.split.el.getWidth();
46649 updateBox : function(box){
46650 if(this.split && !this.collapsed){
46651 var sw = this.split.el.getWidth();
46653 this.split.el.setLeft(box.x+box.width);
46654 this.split.el.setTop(box.y);
46655 this.split.el.setHeight(box.height);
46657 if(this.collapsed){
46658 this.updateBody(null, box.height);
46660 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46665 * Ext JS Library 1.1.1
46666 * Copyright(c) 2006-2007, Ext JS, LLC.
46668 * Originally Released Under LGPL - original licence link has changed is not relivant.
46671 * <script type="text/javascript">
46676 * Private internal class for reading and applying state
46678 Roo.LayoutStateManager = function(layout){
46679 // default empty state
46688 Roo.LayoutStateManager.prototype = {
46689 init : function(layout, provider){
46690 this.provider = provider;
46691 var state = provider.get(layout.id+"-layout-state");
46693 var wasUpdating = layout.isUpdating();
46695 layout.beginUpdate();
46697 for(var key in state){
46698 if(typeof state[key] != "function"){
46699 var rstate = state[key];
46700 var r = layout.getRegion(key);
46703 r.resizeTo(rstate.size);
46705 if(rstate.collapsed == true){
46708 r.expand(null, true);
46714 layout.endUpdate();
46716 this.state = state;
46718 this.layout = layout;
46719 layout.on("regionresized", this.onRegionResized, this);
46720 layout.on("regioncollapsed", this.onRegionCollapsed, this);
46721 layout.on("regionexpanded", this.onRegionExpanded, this);
46724 storeState : function(){
46725 this.provider.set(this.layout.id+"-layout-state", this.state);
46728 onRegionResized : function(region, newSize){
46729 this.state[region.getPosition()].size = newSize;
46733 onRegionCollapsed : function(region){
46734 this.state[region.getPosition()].collapsed = true;
46738 onRegionExpanded : function(region){
46739 this.state[region.getPosition()].collapsed = false;
46744 * Ext JS Library 1.1.1
46745 * Copyright(c) 2006-2007, Ext JS, LLC.
46747 * Originally Released Under LGPL - original licence link has changed is not relivant.
46750 * <script type="text/javascript">
46753 * @class Roo.ContentPanel
46754 * @extends Roo.util.Observable
46755 * A basic ContentPanel element.
46756 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
46757 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
46758 * @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
46759 * @cfg {Boolean} closable True if the panel can be closed/removed
46760 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
46761 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
46762 * @cfg {Toolbar} toolbar A toolbar for this panel
46763 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
46764 * @cfg {String} title The title for this panel
46765 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
46766 * @cfg {String} url Calls {@link #setUrl} with this value
46767 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
46768 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
46769 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
46770 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
46773 * Create a new ContentPanel.
46774 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
46775 * @param {String/Object} config A string to set only the title or a config object
46776 * @param {String} content (optional) Set the HTML content for this panel
46777 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
46779 Roo.ContentPanel = function(el, config, content){
46783 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
46787 if (config && config.parentLayout) {
46788 el = config.parentLayout.el.createChild();
46791 if(el.autoCreate){ // xtype is available if this is called from factory
46795 this.el = Roo.get(el);
46796 if(!this.el && config && config.autoCreate){
46797 if(typeof config.autoCreate == "object"){
46798 if(!config.autoCreate.id){
46799 config.autoCreate.id = config.id||el;
46801 this.el = Roo.DomHelper.append(document.body,
46802 config.autoCreate, true);
46804 this.el = Roo.DomHelper.append(document.body,
46805 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
46808 this.closable = false;
46809 this.loaded = false;
46810 this.active = false;
46811 if(typeof config == "string"){
46812 this.title = config;
46814 Roo.apply(this, config);
46817 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
46818 this.wrapEl = this.el.wrap();
46819 this.toolbar.container = this.el.insertSibling(false, 'before');
46820 this.toolbar = new Roo.Toolbar(this.toolbar);
46826 this.resizeEl = Roo.get(this.resizeEl, true);
46828 this.resizeEl = this.el;
46833 * Fires when this panel is activated.
46834 * @param {Roo.ContentPanel} this
46838 * @event deactivate
46839 * Fires when this panel is activated.
46840 * @param {Roo.ContentPanel} this
46842 "deactivate" : true,
46846 * Fires when this panel is resized if fitToFrame is true.
46847 * @param {Roo.ContentPanel} this
46848 * @param {Number} width The width after any component adjustments
46849 * @param {Number} height The height after any component adjustments
46855 * Fires when this tab is created
46856 * @param {Roo.ContentPanel} this
46863 if(this.autoScroll){
46864 this.resizeEl.setStyle("overflow", "auto");
46866 // fix randome scrolling
46867 this.el.on('scroll', function() {
46868 Roo.log('fix random scolling');
46869 this.scrollTo('top',0);
46872 content = content || this.content;
46874 this.setContent(content);
46876 if(config && config.url){
46877 this.setUrl(this.url, this.params, this.loadOnce);
46882 Roo.ContentPanel.superclass.constructor.call(this);
46884 this.fireEvent('render', this);
46887 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
46889 setRegion : function(region){
46890 this.region = region;
46892 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
46894 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
46899 * Returns the toolbar for this Panel if one was configured.
46900 * @return {Roo.Toolbar}
46902 getToolbar : function(){
46903 return this.toolbar;
46906 setActiveState : function(active){
46907 this.active = active;
46909 this.fireEvent("deactivate", this);
46911 this.fireEvent("activate", this);
46915 * Updates this panel's element
46916 * @param {String} content The new content
46917 * @param {Boolean} loadScripts (optional) true to look for and process scripts
46919 setContent : function(content, loadScripts){
46920 this.el.update(content, loadScripts);
46923 ignoreResize : function(w, h){
46924 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
46927 this.lastSize = {width: w, height: h};
46932 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
46933 * @return {Roo.UpdateManager} The UpdateManager
46935 getUpdateManager : function(){
46936 return this.el.getUpdateManager();
46939 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
46940 * @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:
46943 url: "your-url.php",
46944 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
46945 callback: yourFunction,
46946 scope: yourObject, //(optional scope)
46949 text: "Loading...",
46954 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
46955 * 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.
46956 * @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}
46957 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
46958 * @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.
46959 * @return {Roo.ContentPanel} this
46962 var um = this.el.getUpdateManager();
46963 um.update.apply(um, arguments);
46969 * 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.
46970 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
46971 * @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)
46972 * @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)
46973 * @return {Roo.UpdateManager} The UpdateManager
46975 setUrl : function(url, params, loadOnce){
46976 if(this.refreshDelegate){
46977 this.removeListener("activate", this.refreshDelegate);
46979 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
46980 this.on("activate", this.refreshDelegate);
46981 return this.el.getUpdateManager();
46984 _handleRefresh : function(url, params, loadOnce){
46985 if(!loadOnce || !this.loaded){
46986 var updater = this.el.getUpdateManager();
46987 updater.update(url, params, this._setLoaded.createDelegate(this));
46991 _setLoaded : function(){
46992 this.loaded = true;
46996 * Returns this panel's id
46999 getId : function(){
47004 * Returns this panel's element - used by regiosn to add.
47005 * @return {Roo.Element}
47007 getEl : function(){
47008 return this.wrapEl || this.el;
47011 adjustForComponents : function(width, height){
47012 if(this.resizeEl != this.el){
47013 width -= this.el.getFrameWidth('lr');
47014 height -= this.el.getFrameWidth('tb');
47017 var te = this.toolbar.getEl();
47018 height -= te.getHeight();
47019 te.setWidth(width);
47021 if(this.adjustments){
47022 width += this.adjustments[0];
47023 height += this.adjustments[1];
47025 return {"width": width, "height": height};
47028 setSize : function(width, height){
47029 if(this.fitToFrame && !this.ignoreResize(width, height)){
47030 if(this.fitContainer && this.resizeEl != this.el){
47031 this.el.setSize(width, height);
47033 var size = this.adjustForComponents(width, height);
47034 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
47035 this.fireEvent('resize', this, size.width, size.height);
47040 * Returns this panel's title
47043 getTitle : function(){
47048 * Set this panel's title
47049 * @param {String} title
47051 setTitle : function(title){
47052 this.title = title;
47054 this.region.updatePanelTitle(this, title);
47059 * Returns true is this panel was configured to be closable
47060 * @return {Boolean}
47062 isClosable : function(){
47063 return this.closable;
47066 beforeSlide : function(){
47068 this.resizeEl.clip();
47071 afterSlide : function(){
47073 this.resizeEl.unclip();
47077 * Force a content refresh from the URL specified in the {@link #setUrl} method.
47078 * Will fail silently if the {@link #setUrl} method has not been called.
47079 * This does not activate the panel, just updates its content.
47081 refresh : function(){
47082 if(this.refreshDelegate){
47083 this.loaded = false;
47084 this.refreshDelegate();
47089 * Destroys this panel
47091 destroy : function(){
47092 this.el.removeAllListeners();
47093 var tempEl = document.createElement("span");
47094 tempEl.appendChild(this.el.dom);
47095 tempEl.innerHTML = "";
47101 * form - if the content panel contains a form - this is a reference to it.
47102 * @type {Roo.form.Form}
47106 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
47107 * This contains a reference to it.
47113 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
47123 * @param {Object} cfg Xtype definition of item to add.
47126 addxtype : function(cfg) {
47128 if (cfg.xtype.match(/^Form$/)) {
47129 var el = this.el.createChild();
47131 this.form = new Roo.form.Form(cfg);
47134 if ( this.form.allItems.length) this.form.render(el.dom);
47137 // should only have one of theses..
47138 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
47140 cfg.el = this.el.appendChild(document.createElement("div"));
47143 var ret = new Roo.factory(cfg);
47144 ret.render && ret.render(false, ''); // render blank..
47153 * @class Roo.GridPanel
47154 * @extends Roo.ContentPanel
47156 * Create a new GridPanel.
47157 * @param {Roo.grid.Grid} grid The grid for this panel
47158 * @param {String/Object} config A string to set only the panel's title, or a config object
47160 Roo.GridPanel = function(grid, config){
47163 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
47164 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
47166 this.wrapper.dom.appendChild(grid.getGridEl().dom);
47168 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
47171 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
47173 // xtype created footer. - not sure if will work as we normally have to render first..
47174 if (this.footer && !this.footer.el && this.footer.xtype) {
47176 this.footer.container = this.grid.getView().getFooterPanel(true);
47177 this.footer.dataSource = this.grid.dataSource;
47178 this.footer = Roo.factory(this.footer, Roo);
47182 grid.monitorWindowResize = false; // turn off autosizing
47183 grid.autoHeight = false;
47184 grid.autoWidth = false;
47186 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
47189 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
47190 getId : function(){
47191 return this.grid.id;
47195 * Returns the grid for this panel
47196 * @return {Roo.grid.Grid}
47198 getGrid : function(){
47202 setSize : function(width, height){
47203 if(!this.ignoreResize(width, height)){
47204 var grid = this.grid;
47205 var size = this.adjustForComponents(width, height);
47206 grid.getGridEl().setSize(size.width, size.height);
47211 beforeSlide : function(){
47212 this.grid.getView().scroller.clip();
47215 afterSlide : function(){
47216 this.grid.getView().scroller.unclip();
47219 destroy : function(){
47220 this.grid.destroy();
47222 Roo.GridPanel.superclass.destroy.call(this);
47228 * @class Roo.NestedLayoutPanel
47229 * @extends Roo.ContentPanel
47231 * Create a new NestedLayoutPanel.
47234 * @param {Roo.BorderLayout} layout The layout for this panel
47235 * @param {String/Object} config A string to set only the title or a config object
47237 Roo.NestedLayoutPanel = function(layout, config)
47239 // construct with only one argument..
47240 /* FIXME - implement nicer consturctors
47241 if (layout.layout) {
47243 layout = config.layout;
47244 delete config.layout;
47246 if (layout.xtype && !layout.getEl) {
47247 // then layout needs constructing..
47248 layout = Roo.factory(layout, Roo);
47253 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
47255 layout.monitorWindowResize = false; // turn off autosizing
47256 this.layout = layout;
47257 this.layout.getEl().addClass("x-layout-nested-layout");
47264 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
47266 setSize : function(width, height){
47267 if(!this.ignoreResize(width, height)){
47268 var size = this.adjustForComponents(width, height);
47269 var el = this.layout.getEl();
47270 el.setSize(size.width, size.height);
47271 var touch = el.dom.offsetWidth;
47272 this.layout.layout();
47273 // ie requires a double layout on the first pass
47274 if(Roo.isIE && !this.initialized){
47275 this.initialized = true;
47276 this.layout.layout();
47281 // activate all subpanels if not currently active..
47283 setActiveState : function(active){
47284 this.active = active;
47286 this.fireEvent("deactivate", this);
47290 this.fireEvent("activate", this);
47291 // not sure if this should happen before or after..
47292 if (!this.layout) {
47293 return; // should not happen..
47296 for (var r in this.layout.regions) {
47297 reg = this.layout.getRegion(r);
47298 if (reg.getActivePanel()) {
47299 //reg.showPanel(reg.getActivePanel()); // force it to activate..
47300 reg.setActivePanel(reg.getActivePanel());
47303 if (!reg.panels.length) {
47306 reg.showPanel(reg.getPanel(0));
47315 * Returns the nested BorderLayout for this panel
47316 * @return {Roo.BorderLayout}
47318 getLayout : function(){
47319 return this.layout;
47323 * Adds a xtype elements to the layout of the nested panel
47327 xtype : 'ContentPanel',
47334 xtype : 'NestedLayoutPanel',
47340 items : [ ... list of content panels or nested layout panels.. ]
47344 * @param {Object} cfg Xtype definition of item to add.
47346 addxtype : function(cfg) {
47347 return this.layout.addxtype(cfg);
47352 Roo.ScrollPanel = function(el, config, content){
47353 config = config || {};
47354 config.fitToFrame = true;
47355 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
47357 this.el.dom.style.overflow = "hidden";
47358 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
47359 this.el.removeClass("x-layout-inactive-content");
47360 this.el.on("mousewheel", this.onWheel, this);
47362 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
47363 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
47364 up.unselectable(); down.unselectable();
47365 up.on("click", this.scrollUp, this);
47366 down.on("click", this.scrollDown, this);
47367 up.addClassOnOver("x-scroller-btn-over");
47368 down.addClassOnOver("x-scroller-btn-over");
47369 up.addClassOnClick("x-scroller-btn-click");
47370 down.addClassOnClick("x-scroller-btn-click");
47371 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
47373 this.resizeEl = this.el;
47374 this.el = wrap; this.up = up; this.down = down;
47377 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
47379 wheelIncrement : 5,
47380 scrollUp : function(){
47381 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
47384 scrollDown : function(){
47385 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
47388 afterScroll : function(){
47389 var el = this.resizeEl;
47390 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
47391 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47392 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47395 setSize : function(){
47396 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
47397 this.afterScroll();
47400 onWheel : function(e){
47401 var d = e.getWheelDelta();
47402 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
47403 this.afterScroll();
47407 setContent : function(content, loadScripts){
47408 this.resizeEl.update(content, loadScripts);
47422 * @class Roo.TreePanel
47423 * @extends Roo.ContentPanel
47425 * Create a new TreePanel. - defaults to fit/scoll contents.
47426 * @param {String/Object} config A string to set only the panel's title, or a config object
47427 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
47429 Roo.TreePanel = function(config){
47430 var el = config.el;
47431 var tree = config.tree;
47432 delete config.tree;
47433 delete config.el; // hopefull!
47435 // wrapper for IE7 strict & safari scroll issue
47437 var treeEl = el.createChild();
47438 config.resizeEl = treeEl;
47442 Roo.TreePanel.superclass.constructor.call(this, el, config);
47445 this.tree = new Roo.tree.TreePanel(treeEl , tree);
47446 //console.log(tree);
47447 this.on('activate', function()
47449 if (this.tree.rendered) {
47452 //console.log('render tree');
47453 this.tree.render();
47456 this.on('resize', function (cp, w, h) {
47457 this.tree.innerCt.setWidth(w);
47458 this.tree.innerCt.setHeight(h);
47459 this.tree.innerCt.setStyle('overflow-y', 'auto');
47466 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
47483 * Ext JS Library 1.1.1
47484 * Copyright(c) 2006-2007, Ext JS, LLC.
47486 * Originally Released Under LGPL - original licence link has changed is not relivant.
47489 * <script type="text/javascript">
47494 * @class Roo.ReaderLayout
47495 * @extends Roo.BorderLayout
47496 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
47497 * center region containing two nested regions (a top one for a list view and one for item preview below),
47498 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
47499 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
47500 * expedites the setup of the overall layout and regions for this common application style.
47503 var reader = new Roo.ReaderLayout();
47504 var CP = Roo.ContentPanel; // shortcut for adding
47506 reader.beginUpdate();
47507 reader.add("north", new CP("north", "North"));
47508 reader.add("west", new CP("west", {title: "West"}));
47509 reader.add("east", new CP("east", {title: "East"}));
47511 reader.regions.listView.add(new CP("listView", "List"));
47512 reader.regions.preview.add(new CP("preview", "Preview"));
47513 reader.endUpdate();
47516 * Create a new ReaderLayout
47517 * @param {Object} config Configuration options
47518 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
47519 * document.body if omitted)
47521 Roo.ReaderLayout = function(config, renderTo){
47522 var c = config || {size:{}};
47523 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
47524 north: c.north !== false ? Roo.apply({
47528 }, c.north) : false,
47529 west: c.west !== false ? Roo.apply({
47537 margins:{left:5,right:0,bottom:5,top:5},
47538 cmargins:{left:5,right:5,bottom:5,top:5}
47539 }, c.west) : false,
47540 east: c.east !== false ? Roo.apply({
47548 margins:{left:0,right:5,bottom:5,top:5},
47549 cmargins:{left:5,right:5,bottom:5,top:5}
47550 }, c.east) : false,
47551 center: Roo.apply({
47552 tabPosition: 'top',
47556 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
47560 this.el.addClass('x-reader');
47562 this.beginUpdate();
47564 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
47565 south: c.preview !== false ? Roo.apply({
47572 cmargins:{top:5,left:0, right:0, bottom:0}
47573 }, c.preview) : false,
47574 center: Roo.apply({
47580 this.add('center', new Roo.NestedLayoutPanel(inner,
47581 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
47585 this.regions.preview = inner.getRegion('south');
47586 this.regions.listView = inner.getRegion('center');
47589 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
47591 * Ext JS Library 1.1.1
47592 * Copyright(c) 2006-2007, Ext JS, LLC.
47594 * Originally Released Under LGPL - original licence link has changed is not relivant.
47597 * <script type="text/javascript">
47601 * @class Roo.grid.Grid
47602 * @extends Roo.util.Observable
47603 * This class represents the primary interface of a component based grid control.
47604 * <br><br>Usage:<pre><code>
47605 var grid = new Roo.grid.Grid("my-container-id", {
47608 selModel: mySelectionModel,
47609 autoSizeColumns: true,
47610 monitorWindowResize: false,
47611 trackMouseOver: true
47616 * <b>Common Problems:</b><br/>
47617 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
47618 * element will correct this<br/>
47619 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
47620 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
47621 * are unpredictable.<br/>
47622 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
47623 * grid to calculate dimensions/offsets.<br/>
47625 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
47626 * The container MUST have some type of size defined for the grid to fill. The container will be
47627 * automatically set to position relative if it isn't already.
47628 * @param {Object} config A config object that sets properties on this grid.
47630 Roo.grid.Grid = function(container, config){
47631 // initialize the container
47632 this.container = Roo.get(container);
47633 this.container.update("");
47634 this.container.setStyle("overflow", "hidden");
47635 this.container.addClass('x-grid-container');
47637 this.id = this.container.id;
47639 Roo.apply(this, config);
47640 // check and correct shorthanded configs
47642 this.dataSource = this.ds;
47646 this.colModel = this.cm;
47650 this.selModel = this.sm;
47654 if (this.selModel) {
47655 this.selModel = Roo.factory(this.selModel, Roo.grid);
47656 this.sm = this.selModel;
47657 this.sm.xmodule = this.xmodule || false;
47659 if (typeof(this.colModel.config) == 'undefined') {
47660 this.colModel = new Roo.grid.ColumnModel(this.colModel);
47661 this.cm = this.colModel;
47662 this.cm.xmodule = this.xmodule || false;
47664 if (this.dataSource) {
47665 this.dataSource= Roo.factory(this.dataSource, Roo.data);
47666 this.ds = this.dataSource;
47667 this.ds.xmodule = this.xmodule || false;
47674 this.container.setWidth(this.width);
47678 this.container.setHeight(this.height);
47685 * The raw click event for the entire grid.
47686 * @param {Roo.EventObject} e
47691 * The raw dblclick event for the entire grid.
47692 * @param {Roo.EventObject} e
47696 * @event contextmenu
47697 * The raw contextmenu event for the entire grid.
47698 * @param {Roo.EventObject} e
47700 "contextmenu" : true,
47703 * The raw mousedown event for the entire grid.
47704 * @param {Roo.EventObject} e
47706 "mousedown" : true,
47709 * The raw mouseup event for the entire grid.
47710 * @param {Roo.EventObject} e
47715 * The raw mouseover event for the entire grid.
47716 * @param {Roo.EventObject} e
47718 "mouseover" : true,
47721 * The raw mouseout event for the entire grid.
47722 * @param {Roo.EventObject} e
47727 * The raw keypress event for the entire grid.
47728 * @param {Roo.EventObject} e
47733 * The raw keydown event for the entire grid.
47734 * @param {Roo.EventObject} e
47742 * Fires when a cell is clicked
47743 * @param {Grid} this
47744 * @param {Number} rowIndex
47745 * @param {Number} columnIndex
47746 * @param {Roo.EventObject} e
47748 "cellclick" : true,
47750 * @event celldblclick
47751 * Fires when a cell is double clicked
47752 * @param {Grid} this
47753 * @param {Number} rowIndex
47754 * @param {Number} columnIndex
47755 * @param {Roo.EventObject} e
47757 "celldblclick" : true,
47760 * Fires when a row is clicked
47761 * @param {Grid} this
47762 * @param {Number} rowIndex
47763 * @param {Roo.EventObject} e
47767 * @event rowdblclick
47768 * Fires when a row is double clicked
47769 * @param {Grid} this
47770 * @param {Number} rowIndex
47771 * @param {Roo.EventObject} e
47773 "rowdblclick" : true,
47775 * @event headerclick
47776 * Fires when a header is clicked
47777 * @param {Grid} this
47778 * @param {Number} columnIndex
47779 * @param {Roo.EventObject} e
47781 "headerclick" : true,
47783 * @event headerdblclick
47784 * Fires when a header cell is double clicked
47785 * @param {Grid} this
47786 * @param {Number} columnIndex
47787 * @param {Roo.EventObject} e
47789 "headerdblclick" : true,
47791 * @event rowcontextmenu
47792 * Fires when a row is right clicked
47793 * @param {Grid} this
47794 * @param {Number} rowIndex
47795 * @param {Roo.EventObject} e
47797 "rowcontextmenu" : true,
47799 * @event cellcontextmenu
47800 * Fires when a cell is right clicked
47801 * @param {Grid} this
47802 * @param {Number} rowIndex
47803 * @param {Number} cellIndex
47804 * @param {Roo.EventObject} e
47806 "cellcontextmenu" : true,
47808 * @event headercontextmenu
47809 * Fires when a header is right clicked
47810 * @param {Grid} this
47811 * @param {Number} columnIndex
47812 * @param {Roo.EventObject} e
47814 "headercontextmenu" : true,
47816 * @event bodyscroll
47817 * Fires when the body element is scrolled
47818 * @param {Number} scrollLeft
47819 * @param {Number} scrollTop
47821 "bodyscroll" : true,
47823 * @event columnresize
47824 * Fires when the user resizes a column
47825 * @param {Number} columnIndex
47826 * @param {Number} newSize
47828 "columnresize" : true,
47830 * @event columnmove
47831 * Fires when the user moves a column
47832 * @param {Number} oldIndex
47833 * @param {Number} newIndex
47835 "columnmove" : true,
47838 * Fires when row(s) start being dragged
47839 * @param {Grid} this
47840 * @param {Roo.GridDD} dd The drag drop object
47841 * @param {event} e The raw browser event
47843 "startdrag" : true,
47846 * Fires when a drag operation is complete
47847 * @param {Grid} this
47848 * @param {Roo.GridDD} dd The drag drop object
47849 * @param {event} e The raw browser event
47854 * Fires when dragged row(s) are dropped on a valid DD target
47855 * @param {Grid} this
47856 * @param {Roo.GridDD} dd The drag drop object
47857 * @param {String} targetId The target drag drop object
47858 * @param {event} e The raw browser event
47863 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
47864 * @param {Grid} this
47865 * @param {Roo.GridDD} dd The drag drop object
47866 * @param {String} targetId The target drag drop object
47867 * @param {event} e The raw browser event
47872 * Fires when the dragged row(s) first cross another DD target while being dragged
47873 * @param {Grid} this
47874 * @param {Roo.GridDD} dd The drag drop object
47875 * @param {String} targetId The target drag drop object
47876 * @param {event} e The raw browser event
47878 "dragenter" : true,
47881 * Fires when the dragged row(s) leave another DD target while being dragged
47882 * @param {Grid} this
47883 * @param {Roo.GridDD} dd The drag drop object
47884 * @param {String} targetId The target drag drop object
47885 * @param {event} e The raw browser event
47890 * Fires when a row is rendered, so you can change add a style to it.
47891 * @param {GridView} gridview The grid view
47892 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
47898 * Fires when the grid is rendered
47899 * @param {Grid} grid
47904 Roo.grid.Grid.superclass.constructor.call(this);
47906 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
47909 * @cfg {String} ddGroup - drag drop group.
47913 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
47915 minColumnWidth : 25,
47918 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
47919 * <b>on initial render.</b> It is more efficient to explicitly size the columns
47920 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
47922 autoSizeColumns : false,
47925 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
47927 autoSizeHeaders : true,
47930 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
47932 monitorWindowResize : true,
47935 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
47936 * rows measured to get a columns size. Default is 0 (all rows).
47938 maxRowsToMeasure : 0,
47941 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
47943 trackMouseOver : true,
47946 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
47950 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
47952 enableDragDrop : false,
47955 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
47957 enableColumnMove : true,
47960 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
47962 enableColumnHide : true,
47965 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
47967 enableRowHeightSync : false,
47970 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
47975 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
47977 autoHeight : false,
47980 * @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.
47982 autoExpandColumn : false,
47985 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
47988 autoExpandMin : 50,
47991 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
47993 autoExpandMax : 1000,
47996 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
48001 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
48005 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
48015 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
48016 * of a fixed width. Default is false.
48019 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
48022 * Called once after all setup has been completed and the grid is ready to be rendered.
48023 * @return {Roo.grid.Grid} this
48025 render : function()
48027 var c = this.container;
48028 // try to detect autoHeight/width mode
48029 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
48030 this.autoHeight = true;
48032 var view = this.getView();
48035 c.on("click", this.onClick, this);
48036 c.on("dblclick", this.onDblClick, this);
48037 c.on("contextmenu", this.onContextMenu, this);
48038 c.on("keydown", this.onKeyDown, this);
48040 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
48042 this.getSelectionModel().init(this);
48047 this.loadMask = new Roo.LoadMask(this.container,
48048 Roo.apply({store:this.dataSource}, this.loadMask));
48052 if (this.toolbar && this.toolbar.xtype) {
48053 this.toolbar.container = this.getView().getHeaderPanel(true);
48054 this.toolbar = new Roo.Toolbar(this.toolbar);
48056 if (this.footer && this.footer.xtype) {
48057 this.footer.dataSource = this.getDataSource();
48058 this.footer.container = this.getView().getFooterPanel(true);
48059 this.footer = Roo.factory(this.footer, Roo);
48061 if (this.dropTarget && this.dropTarget.xtype) {
48062 delete this.dropTarget.xtype;
48063 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
48067 this.rendered = true;
48068 this.fireEvent('render', this);
48073 * Reconfigures the grid to use a different Store and Column Model.
48074 * The View will be bound to the new objects and refreshed.
48075 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
48076 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
48078 reconfigure : function(dataSource, colModel){
48080 this.loadMask.destroy();
48081 this.loadMask = new Roo.LoadMask(this.container,
48082 Roo.apply({store:dataSource}, this.loadMask));
48084 this.view.bind(dataSource, colModel);
48085 this.dataSource = dataSource;
48086 this.colModel = colModel;
48087 this.view.refresh(true);
48091 onKeyDown : function(e){
48092 this.fireEvent("keydown", e);
48096 * Destroy this grid.
48097 * @param {Boolean} removeEl True to remove the element
48099 destroy : function(removeEl, keepListeners){
48101 this.loadMask.destroy();
48103 var c = this.container;
48104 c.removeAllListeners();
48105 this.view.destroy();
48106 this.colModel.purgeListeners();
48107 if(!keepListeners){
48108 this.purgeListeners();
48111 if(removeEl === true){
48117 processEvent : function(name, e){
48118 this.fireEvent(name, e);
48119 var t = e.getTarget();
48121 var header = v.findHeaderIndex(t);
48122 if(header !== false){
48123 this.fireEvent("header" + name, this, header, e);
48125 var row = v.findRowIndex(t);
48126 var cell = v.findCellIndex(t);
48128 this.fireEvent("row" + name, this, row, e);
48129 if(cell !== false){
48130 this.fireEvent("cell" + name, this, row, cell, e);
48137 onClick : function(e){
48138 this.processEvent("click", e);
48142 onContextMenu : function(e, t){
48143 this.processEvent("contextmenu", e);
48147 onDblClick : function(e){
48148 this.processEvent("dblclick", e);
48152 walkCells : function(row, col, step, fn, scope){
48153 var cm = this.colModel, clen = cm.getColumnCount();
48154 var ds = this.dataSource, rlen = ds.getCount(), first = true;
48166 if(fn.call(scope || this, row, col, cm) === true){
48184 if(fn.call(scope || this, row, col, cm) === true){
48196 getSelections : function(){
48197 return this.selModel.getSelections();
48201 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
48202 * but if manual update is required this method will initiate it.
48204 autoSize : function(){
48206 this.view.layout();
48207 if(this.view.adjustForScroll){
48208 this.view.adjustForScroll();
48214 * Returns the grid's underlying element.
48215 * @return {Element} The element
48217 getGridEl : function(){
48218 return this.container;
48221 // private for compatibility, overridden by editor grid
48222 stopEditing : function(){},
48225 * Returns the grid's SelectionModel.
48226 * @return {SelectionModel}
48228 getSelectionModel : function(){
48229 if(!this.selModel){
48230 this.selModel = new Roo.grid.RowSelectionModel();
48232 return this.selModel;
48236 * Returns the grid's DataSource.
48237 * @return {DataSource}
48239 getDataSource : function(){
48240 return this.dataSource;
48244 * Returns the grid's ColumnModel.
48245 * @return {ColumnModel}
48247 getColumnModel : function(){
48248 return this.colModel;
48252 * Returns the grid's GridView object.
48253 * @return {GridView}
48255 getView : function(){
48257 this.view = new Roo.grid.GridView(this.viewConfig);
48262 * Called to get grid's drag proxy text, by default returns this.ddText.
48265 getDragDropText : function(){
48266 var count = this.selModel.getCount();
48267 return String.format(this.ddText, count, count == 1 ? '' : 's');
48271 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
48272 * %0 is replaced with the number of selected rows.
48275 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
48277 * Ext JS Library 1.1.1
48278 * Copyright(c) 2006-2007, Ext JS, LLC.
48280 * Originally Released Under LGPL - original licence link has changed is not relivant.
48283 * <script type="text/javascript">
48286 Roo.grid.AbstractGridView = function(){
48290 "beforerowremoved" : true,
48291 "beforerowsinserted" : true,
48292 "beforerefresh" : true,
48293 "rowremoved" : true,
48294 "rowsinserted" : true,
48295 "rowupdated" : true,
48298 Roo.grid.AbstractGridView.superclass.constructor.call(this);
48301 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
48302 rowClass : "x-grid-row",
48303 cellClass : "x-grid-cell",
48304 tdClass : "x-grid-td",
48305 hdClass : "x-grid-hd",
48306 splitClass : "x-grid-hd-split",
48308 init: function(grid){
48310 var cid = this.grid.getGridEl().id;
48311 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
48312 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
48313 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
48314 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
48317 getColumnRenderers : function(){
48318 var renderers = [];
48319 var cm = this.grid.colModel;
48320 var colCount = cm.getColumnCount();
48321 for(var i = 0; i < colCount; i++){
48322 renderers[i] = cm.getRenderer(i);
48327 getColumnIds : function(){
48329 var cm = this.grid.colModel;
48330 var colCount = cm.getColumnCount();
48331 for(var i = 0; i < colCount; i++){
48332 ids[i] = cm.getColumnId(i);
48337 getDataIndexes : function(){
48338 if(!this.indexMap){
48339 this.indexMap = this.buildIndexMap();
48341 return this.indexMap.colToData;
48344 getColumnIndexByDataIndex : function(dataIndex){
48345 if(!this.indexMap){
48346 this.indexMap = this.buildIndexMap();
48348 return this.indexMap.dataToCol[dataIndex];
48352 * Set a css style for a column dynamically.
48353 * @param {Number} colIndex The index of the column
48354 * @param {String} name The css property name
48355 * @param {String} value The css value
48357 setCSSStyle : function(colIndex, name, value){
48358 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
48359 Roo.util.CSS.updateRule(selector, name, value);
48362 generateRules : function(cm){
48363 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
48364 Roo.util.CSS.removeStyleSheet(rulesId);
48365 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48366 var cid = cm.getColumnId(i);
48367 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
48368 this.tdSelector, cid, " {\n}\n",
48369 this.hdSelector, cid, " {\n}\n",
48370 this.splitSelector, cid, " {\n}\n");
48372 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48376 * Ext JS Library 1.1.1
48377 * Copyright(c) 2006-2007, Ext JS, LLC.
48379 * Originally Released Under LGPL - original licence link has changed is not relivant.
48382 * <script type="text/javascript">
48386 // This is a support class used internally by the Grid components
48387 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
48389 this.view = grid.getView();
48390 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48391 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
48393 this.setHandleElId(Roo.id(hd));
48394 this.setOuterHandleElId(Roo.id(hd2));
48396 this.scroll = false;
48398 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
48400 getDragData : function(e){
48401 var t = Roo.lib.Event.getTarget(e);
48402 var h = this.view.findHeaderCell(t);
48404 return {ddel: h.firstChild, header:h};
48409 onInitDrag : function(e){
48410 this.view.headersDisabled = true;
48411 var clone = this.dragData.ddel.cloneNode(true);
48412 clone.id = Roo.id();
48413 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
48414 this.proxy.update(clone);
48418 afterValidDrop : function(){
48420 setTimeout(function(){
48421 v.headersDisabled = false;
48425 afterInvalidDrop : function(){
48427 setTimeout(function(){
48428 v.headersDisabled = false;
48434 * Ext JS Library 1.1.1
48435 * Copyright(c) 2006-2007, Ext JS, LLC.
48437 * Originally Released Under LGPL - original licence link has changed is not relivant.
48440 * <script type="text/javascript">
48443 // This is a support class used internally by the Grid components
48444 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
48446 this.view = grid.getView();
48447 // split the proxies so they don't interfere with mouse events
48448 this.proxyTop = Roo.DomHelper.append(document.body, {
48449 cls:"col-move-top", html:" "
48451 this.proxyBottom = Roo.DomHelper.append(document.body, {
48452 cls:"col-move-bottom", html:" "
48454 this.proxyTop.hide = this.proxyBottom.hide = function(){
48455 this.setLeftTop(-100,-100);
48456 this.setStyle("visibility", "hidden");
48458 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48459 // temporarily disabled
48460 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
48461 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
48463 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
48464 proxyOffsets : [-4, -9],
48465 fly: Roo.Element.fly,
48467 getTargetFromEvent : function(e){
48468 var t = Roo.lib.Event.getTarget(e);
48469 var cindex = this.view.findCellIndex(t);
48470 if(cindex !== false){
48471 return this.view.getHeaderCell(cindex);
48476 nextVisible : function(h){
48477 var v = this.view, cm = this.grid.colModel;
48480 if(!cm.isHidden(v.getCellIndex(h))){
48488 prevVisible : function(h){
48489 var v = this.view, cm = this.grid.colModel;
48492 if(!cm.isHidden(v.getCellIndex(h))){
48500 positionIndicator : function(h, n, e){
48501 var x = Roo.lib.Event.getPageX(e);
48502 var r = Roo.lib.Dom.getRegion(n.firstChild);
48503 var px, pt, py = r.top + this.proxyOffsets[1];
48504 if((r.right - x) <= (r.right-r.left)/2){
48505 px = r.right+this.view.borderWidth;
48511 var oldIndex = this.view.getCellIndex(h);
48512 var newIndex = this.view.getCellIndex(n);
48514 if(this.grid.colModel.isFixed(newIndex)){
48518 var locked = this.grid.colModel.isLocked(newIndex);
48523 if(oldIndex < newIndex){
48526 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
48529 px += this.proxyOffsets[0];
48530 this.proxyTop.setLeftTop(px, py);
48531 this.proxyTop.show();
48532 if(!this.bottomOffset){
48533 this.bottomOffset = this.view.mainHd.getHeight();
48535 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
48536 this.proxyBottom.show();
48540 onNodeEnter : function(n, dd, e, data){
48541 if(data.header != n){
48542 this.positionIndicator(data.header, n, e);
48546 onNodeOver : function(n, dd, e, data){
48547 var result = false;
48548 if(data.header != n){
48549 result = this.positionIndicator(data.header, n, e);
48552 this.proxyTop.hide();
48553 this.proxyBottom.hide();
48555 return result ? this.dropAllowed : this.dropNotAllowed;
48558 onNodeOut : function(n, dd, e, data){
48559 this.proxyTop.hide();
48560 this.proxyBottom.hide();
48563 onNodeDrop : function(n, dd, e, data){
48564 var h = data.header;
48566 var cm = this.grid.colModel;
48567 var x = Roo.lib.Event.getPageX(e);
48568 var r = Roo.lib.Dom.getRegion(n.firstChild);
48569 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
48570 var oldIndex = this.view.getCellIndex(h);
48571 var newIndex = this.view.getCellIndex(n);
48572 var locked = cm.isLocked(newIndex);
48576 if(oldIndex < newIndex){
48579 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
48582 cm.setLocked(oldIndex, locked, true);
48583 cm.moveColumn(oldIndex, newIndex);
48584 this.grid.fireEvent("columnmove", oldIndex, newIndex);
48592 * Ext JS Library 1.1.1
48593 * Copyright(c) 2006-2007, Ext JS, LLC.
48595 * Originally Released Under LGPL - original licence link has changed is not relivant.
48598 * <script type="text/javascript">
48602 * @class Roo.grid.GridView
48603 * @extends Roo.util.Observable
48606 * @param {Object} config
48608 Roo.grid.GridView = function(config){
48609 Roo.grid.GridView.superclass.constructor.call(this);
48612 Roo.apply(this, config);
48615 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
48618 rowClass : "x-grid-row",
48620 cellClass : "x-grid-col",
48622 tdClass : "x-grid-td",
48624 hdClass : "x-grid-hd",
48626 splitClass : "x-grid-split",
48628 sortClasses : ["sort-asc", "sort-desc"],
48630 enableMoveAnim : false,
48634 dh : Roo.DomHelper,
48636 fly : Roo.Element.fly,
48638 css : Roo.util.CSS,
48644 scrollIncrement : 22,
48646 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
48648 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
48650 bind : function(ds, cm){
48652 this.ds.un("load", this.onLoad, this);
48653 this.ds.un("datachanged", this.onDataChange, this);
48654 this.ds.un("add", this.onAdd, this);
48655 this.ds.un("remove", this.onRemove, this);
48656 this.ds.un("update", this.onUpdate, this);
48657 this.ds.un("clear", this.onClear, this);
48660 ds.on("load", this.onLoad, this);
48661 ds.on("datachanged", this.onDataChange, this);
48662 ds.on("add", this.onAdd, this);
48663 ds.on("remove", this.onRemove, this);
48664 ds.on("update", this.onUpdate, this);
48665 ds.on("clear", this.onClear, this);
48670 this.cm.un("widthchange", this.onColWidthChange, this);
48671 this.cm.un("headerchange", this.onHeaderChange, this);
48672 this.cm.un("hiddenchange", this.onHiddenChange, this);
48673 this.cm.un("columnmoved", this.onColumnMove, this);
48674 this.cm.un("columnlockchange", this.onColumnLock, this);
48677 this.generateRules(cm);
48678 cm.on("widthchange", this.onColWidthChange, this);
48679 cm.on("headerchange", this.onHeaderChange, this);
48680 cm.on("hiddenchange", this.onHiddenChange, this);
48681 cm.on("columnmoved", this.onColumnMove, this);
48682 cm.on("columnlockchange", this.onColumnLock, this);
48687 init: function(grid){
48688 Roo.grid.GridView.superclass.init.call(this, grid);
48690 this.bind(grid.dataSource, grid.colModel);
48692 grid.on("headerclick", this.handleHeaderClick, this);
48694 if(grid.trackMouseOver){
48695 grid.on("mouseover", this.onRowOver, this);
48696 grid.on("mouseout", this.onRowOut, this);
48698 grid.cancelTextSelection = function(){};
48699 this.gridId = grid.id;
48701 var tpls = this.templates || {};
48704 tpls.master = new Roo.Template(
48705 '<div class="x-grid" hidefocus="true">',
48706 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
48707 '<div class="x-grid-topbar"></div>',
48708 '<div class="x-grid-scroller"><div></div></div>',
48709 '<div class="x-grid-locked">',
48710 '<div class="x-grid-header">{lockedHeader}</div>',
48711 '<div class="x-grid-body">{lockedBody}</div>',
48713 '<div class="x-grid-viewport">',
48714 '<div class="x-grid-header">{header}</div>',
48715 '<div class="x-grid-body">{body}</div>',
48717 '<div class="x-grid-bottombar"></div>',
48719 '<div class="x-grid-resize-proxy"> </div>',
48722 tpls.master.disableformats = true;
48726 tpls.header = new Roo.Template(
48727 '<table border="0" cellspacing="0" cellpadding="0">',
48728 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
48731 tpls.header.disableformats = true;
48733 tpls.header.compile();
48736 tpls.hcell = new Roo.Template(
48737 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
48738 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
48741 tpls.hcell.disableFormats = true;
48743 tpls.hcell.compile();
48746 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
48747 tpls.hsplit.disableFormats = true;
48749 tpls.hsplit.compile();
48752 tpls.body = new Roo.Template(
48753 '<table border="0" cellspacing="0" cellpadding="0">',
48754 "<tbody>{rows}</tbody>",
48757 tpls.body.disableFormats = true;
48759 tpls.body.compile();
48762 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
48763 tpls.row.disableFormats = true;
48765 tpls.row.compile();
48768 tpls.cell = new Roo.Template(
48769 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
48770 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
48773 tpls.cell.disableFormats = true;
48775 tpls.cell.compile();
48777 this.templates = tpls;
48780 // remap these for backwards compat
48781 onColWidthChange : function(){
48782 this.updateColumns.apply(this, arguments);
48784 onHeaderChange : function(){
48785 this.updateHeaders.apply(this, arguments);
48787 onHiddenChange : function(){
48788 this.handleHiddenChange.apply(this, arguments);
48790 onColumnMove : function(){
48791 this.handleColumnMove.apply(this, arguments);
48793 onColumnLock : function(){
48794 this.handleLockChange.apply(this, arguments);
48797 onDataChange : function(){
48799 this.updateHeaderSortState();
48802 onClear : function(){
48806 onUpdate : function(ds, record){
48807 this.refreshRow(record);
48810 refreshRow : function(record){
48811 var ds = this.ds, index;
48812 if(typeof record == 'number'){
48814 record = ds.getAt(index);
48816 index = ds.indexOf(record);
48818 this.insertRows(ds, index, index, true);
48819 this.onRemove(ds, record, index+1, true);
48820 this.syncRowHeights(index, index);
48822 this.fireEvent("rowupdated", this, index, record);
48825 onAdd : function(ds, records, index){
48826 this.insertRows(ds, index, index + (records.length-1));
48829 onRemove : function(ds, record, index, isUpdate){
48830 if(isUpdate !== true){
48831 this.fireEvent("beforerowremoved", this, index, record);
48833 var bt = this.getBodyTable(), lt = this.getLockedTable();
48834 if(bt.rows[index]){
48835 bt.firstChild.removeChild(bt.rows[index]);
48837 if(lt.rows[index]){
48838 lt.firstChild.removeChild(lt.rows[index]);
48840 if(isUpdate !== true){
48841 this.stripeRows(index);
48842 this.syncRowHeights(index, index);
48844 this.fireEvent("rowremoved", this, index, record);
48848 onLoad : function(){
48849 this.scrollToTop();
48853 * Scrolls the grid to the top
48855 scrollToTop : function(){
48857 this.scroller.dom.scrollTop = 0;
48863 * Gets a panel in the header of the grid that can be used for toolbars etc.
48864 * After modifying the contents of this panel a call to grid.autoSize() may be
48865 * required to register any changes in size.
48866 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
48867 * @return Roo.Element
48869 getHeaderPanel : function(doShow){
48871 this.headerPanel.show();
48873 return this.headerPanel;
48877 * Gets a panel in the footer of the grid that can be used for toolbars etc.
48878 * After modifying the contents of this panel a call to grid.autoSize() may be
48879 * required to register any changes in size.
48880 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
48881 * @return Roo.Element
48883 getFooterPanel : function(doShow){
48885 this.footerPanel.show();
48887 return this.footerPanel;
48890 initElements : function(){
48891 var E = Roo.Element;
48892 var el = this.grid.getGridEl().dom.firstChild;
48893 var cs = el.childNodes;
48895 this.el = new E(el);
48897 this.focusEl = new E(el.firstChild);
48898 this.focusEl.swallowEvent("click", true);
48900 this.headerPanel = new E(cs[1]);
48901 this.headerPanel.enableDisplayMode("block");
48903 this.scroller = new E(cs[2]);
48904 this.scrollSizer = new E(this.scroller.dom.firstChild);
48906 this.lockedWrap = new E(cs[3]);
48907 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
48908 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
48910 this.mainWrap = new E(cs[4]);
48911 this.mainHd = new E(this.mainWrap.dom.firstChild);
48912 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
48914 this.footerPanel = new E(cs[5]);
48915 this.footerPanel.enableDisplayMode("block");
48917 this.resizeProxy = new E(cs[6]);
48919 this.headerSelector = String.format(
48920 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
48921 this.lockedHd.id, this.mainHd.id
48924 this.splitterSelector = String.format(
48925 '#{0} div.x-grid-split, #{1} div.x-grid-split',
48926 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
48929 idToCssName : function(s)
48931 return s.replace(/[^a-z0-9]+/ig, '-');
48934 getHeaderCell : function(index){
48935 return Roo.DomQuery.select(this.headerSelector)[index];
48938 getHeaderCellMeasure : function(index){
48939 return this.getHeaderCell(index).firstChild;
48942 getHeaderCellText : function(index){
48943 return this.getHeaderCell(index).firstChild.firstChild;
48946 getLockedTable : function(){
48947 return this.lockedBody.dom.firstChild;
48950 getBodyTable : function(){
48951 return this.mainBody.dom.firstChild;
48954 getLockedRow : function(index){
48955 return this.getLockedTable().rows[index];
48958 getRow : function(index){
48959 return this.getBodyTable().rows[index];
48962 getRowComposite : function(index){
48964 this.rowEl = new Roo.CompositeElementLite();
48966 var els = [], lrow, mrow;
48967 if(lrow = this.getLockedRow(index)){
48970 if(mrow = this.getRow(index)){
48973 this.rowEl.elements = els;
48977 * Gets the 'td' of the cell
48979 * @param {Integer} rowIndex row to select
48980 * @param {Integer} colIndex column to select
48984 getCell : function(rowIndex, colIndex){
48985 var locked = this.cm.getLockedCount();
48987 if(colIndex < locked){
48988 source = this.lockedBody.dom.firstChild;
48990 source = this.mainBody.dom.firstChild;
48991 colIndex -= locked;
48993 return source.rows[rowIndex].childNodes[colIndex];
48996 getCellText : function(rowIndex, colIndex){
48997 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
49000 getCellBox : function(cell){
49001 var b = this.fly(cell).getBox();
49002 if(Roo.isOpera){ // opera fails to report the Y
49003 b.y = cell.offsetTop + this.mainBody.getY();
49008 getCellIndex : function(cell){
49009 var id = String(cell.className).match(this.cellRE);
49011 return parseInt(id[1], 10);
49016 findHeaderIndex : function(n){
49017 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
49018 return r ? this.getCellIndex(r) : false;
49021 findHeaderCell : function(n){
49022 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
49023 return r ? r : false;
49026 findRowIndex : function(n){
49030 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
49031 return r ? r.rowIndex : false;
49034 findCellIndex : function(node){
49035 var stop = this.el.dom;
49036 while(node && node != stop){
49037 if(this.findRE.test(node.className)){
49038 return this.getCellIndex(node);
49040 node = node.parentNode;
49045 getColumnId : function(index){
49046 return this.cm.getColumnId(index);
49049 getSplitters : function()
49051 if(this.splitterSelector){
49052 return Roo.DomQuery.select(this.splitterSelector);
49058 getSplitter : function(index){
49059 return this.getSplitters()[index];
49062 onRowOver : function(e, t){
49064 if((row = this.findRowIndex(t)) !== false){
49065 this.getRowComposite(row).addClass("x-grid-row-over");
49069 onRowOut : function(e, t){
49071 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
49072 this.getRowComposite(row).removeClass("x-grid-row-over");
49076 renderHeaders : function(){
49078 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
49079 var cb = [], lb = [], sb = [], lsb = [], p = {};
49080 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49081 p.cellId = "x-grid-hd-0-" + i;
49082 p.splitId = "x-grid-csplit-0-" + i;
49083 p.id = cm.getColumnId(i);
49084 p.title = cm.getColumnTooltip(i) || "";
49085 p.value = cm.getColumnHeader(i) || "";
49086 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
49087 if(!cm.isLocked(i)){
49088 cb[cb.length] = ct.apply(p);
49089 sb[sb.length] = st.apply(p);
49091 lb[lb.length] = ct.apply(p);
49092 lsb[lsb.length] = st.apply(p);
49095 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
49096 ht.apply({cells: cb.join(""), splits:sb.join("")})];
49099 updateHeaders : function(){
49100 var html = this.renderHeaders();
49101 this.lockedHd.update(html[0]);
49102 this.mainHd.update(html[1]);
49106 * Focuses the specified row.
49107 * @param {Number} row The row index
49109 focusRow : function(row)
49111 //Roo.log('GridView.focusRow');
49112 var x = this.scroller.dom.scrollLeft;
49113 this.focusCell(row, 0, false);
49114 this.scroller.dom.scrollLeft = x;
49118 * Focuses the specified cell.
49119 * @param {Number} row The row index
49120 * @param {Number} col The column index
49121 * @param {Boolean} hscroll false to disable horizontal scrolling
49123 focusCell : function(row, col, hscroll)
49125 //Roo.log('GridView.focusCell');
49126 var el = this.ensureVisible(row, col, hscroll);
49127 this.focusEl.alignTo(el, "tl-tl");
49129 this.focusEl.focus();
49131 this.focusEl.focus.defer(1, this.focusEl);
49136 * Scrolls the specified cell into view
49137 * @param {Number} row The row index
49138 * @param {Number} col The column index
49139 * @param {Boolean} hscroll false to disable horizontal scrolling
49141 ensureVisible : function(row, col, hscroll)
49143 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
49144 //return null; //disable for testing.
49145 if(typeof row != "number"){
49146 row = row.rowIndex;
49148 if(row < 0 && row >= this.ds.getCount()){
49151 col = (col !== undefined ? col : 0);
49152 var cm = this.grid.colModel;
49153 while(cm.isHidden(col)){
49157 var el = this.getCell(row, col);
49161 var c = this.scroller.dom;
49163 var ctop = parseInt(el.offsetTop, 10);
49164 var cleft = parseInt(el.offsetLeft, 10);
49165 var cbot = ctop + el.offsetHeight;
49166 var cright = cleft + el.offsetWidth;
49168 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
49169 var stop = parseInt(c.scrollTop, 10);
49170 var sleft = parseInt(c.scrollLeft, 10);
49171 var sbot = stop + ch;
49172 var sright = sleft + c.clientWidth;
49174 Roo.log('GridView.ensureVisible:' +
49176 ' c.clientHeight:' + c.clientHeight +
49177 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
49185 c.scrollTop = ctop;
49186 //Roo.log("set scrolltop to ctop DISABLE?");
49187 }else if(cbot > sbot){
49188 //Roo.log("set scrolltop to cbot-ch");
49189 c.scrollTop = cbot-ch;
49192 if(hscroll !== false){
49194 c.scrollLeft = cleft;
49195 }else if(cright > sright){
49196 c.scrollLeft = cright-c.clientWidth;
49203 updateColumns : function(){
49204 this.grid.stopEditing();
49205 var cm = this.grid.colModel, colIds = this.getColumnIds();
49206 //var totalWidth = cm.getTotalWidth();
49208 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49209 //if(cm.isHidden(i)) continue;
49210 var w = cm.getColumnWidth(i);
49211 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
49212 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
49214 this.updateSplitters();
49217 generateRules : function(cm){
49218 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
49219 Roo.util.CSS.removeStyleSheet(rulesId);
49220 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49221 var cid = cm.getColumnId(i);
49223 if(cm.config[i].align){
49224 align = 'text-align:'+cm.config[i].align+';';
49227 if(cm.isHidden(i)){
49228 hidden = 'display:none;';
49230 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
49232 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
49233 this.hdSelector, cid, " {\n", align, width, "}\n",
49234 this.tdSelector, cid, " {\n",hidden,"\n}\n",
49235 this.splitSelector, cid, " {\n", hidden , "\n}\n");
49237 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
49240 updateSplitters : function(){
49241 var cm = this.cm, s = this.getSplitters();
49242 if(s){ // splitters not created yet
49243 var pos = 0, locked = true;
49244 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49245 if(cm.isHidden(i)) continue;
49246 var w = cm.getColumnWidth(i); // make sure it's a number
49247 if(!cm.isLocked(i) && locked){
49252 s[i].style.left = (pos-this.splitOffset) + "px";
49257 handleHiddenChange : function(colModel, colIndex, hidden){
49259 this.hideColumn(colIndex);
49261 this.unhideColumn(colIndex);
49265 hideColumn : function(colIndex){
49266 var cid = this.getColumnId(colIndex);
49267 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
49268 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
49270 this.updateHeaders();
49272 this.updateSplitters();
49276 unhideColumn : function(colIndex){
49277 var cid = this.getColumnId(colIndex);
49278 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
49279 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
49282 this.updateHeaders();
49284 this.updateSplitters();
49288 insertRows : function(dm, firstRow, lastRow, isUpdate){
49289 if(firstRow == 0 && lastRow == dm.getCount()-1){
49293 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
49295 var s = this.getScrollState();
49296 var markup = this.renderRows(firstRow, lastRow);
49297 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
49298 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
49299 this.restoreScroll(s);
49301 this.fireEvent("rowsinserted", this, firstRow, lastRow);
49302 this.syncRowHeights(firstRow, lastRow);
49303 this.stripeRows(firstRow);
49309 bufferRows : function(markup, target, index){
49310 var before = null, trows = target.rows, tbody = target.tBodies[0];
49311 if(index < trows.length){
49312 before = trows[index];
49314 var b = document.createElement("div");
49315 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
49316 var rows = b.firstChild.rows;
49317 for(var i = 0, len = rows.length; i < len; i++){
49319 tbody.insertBefore(rows[0], before);
49321 tbody.appendChild(rows[0]);
49328 deleteRows : function(dm, firstRow, lastRow){
49329 if(dm.getRowCount()<1){
49330 this.fireEvent("beforerefresh", this);
49331 this.mainBody.update("");
49332 this.lockedBody.update("");
49333 this.fireEvent("refresh", this);
49335 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
49336 var bt = this.getBodyTable();
49337 var tbody = bt.firstChild;
49338 var rows = bt.rows;
49339 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
49340 tbody.removeChild(rows[firstRow]);
49342 this.stripeRows(firstRow);
49343 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
49347 updateRows : function(dataSource, firstRow, lastRow){
49348 var s = this.getScrollState();
49350 this.restoreScroll(s);
49353 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
49357 this.updateHeaderSortState();
49360 getScrollState : function(){
49362 var sb = this.scroller.dom;
49363 return {left: sb.scrollLeft, top: sb.scrollTop};
49366 stripeRows : function(startRow){
49367 if(!this.grid.stripeRows || this.ds.getCount() < 1){
49370 startRow = startRow || 0;
49371 var rows = this.getBodyTable().rows;
49372 var lrows = this.getLockedTable().rows;
49373 var cls = ' x-grid-row-alt ';
49374 for(var i = startRow, len = rows.length; i < len; i++){
49375 var row = rows[i], lrow = lrows[i];
49376 var isAlt = ((i+1) % 2 == 0);
49377 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
49378 if(isAlt == hasAlt){
49382 row.className += " x-grid-row-alt";
49384 row.className = row.className.replace("x-grid-row-alt", "");
49387 lrow.className = row.className;
49392 restoreScroll : function(state){
49393 //Roo.log('GridView.restoreScroll');
49394 var sb = this.scroller.dom;
49395 sb.scrollLeft = state.left;
49396 sb.scrollTop = state.top;
49400 syncScroll : function(){
49401 //Roo.log('GridView.syncScroll');
49402 var sb = this.scroller.dom;
49403 var sh = this.mainHd.dom;
49404 var bs = this.mainBody.dom;
49405 var lv = this.lockedBody.dom;
49406 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
49407 lv.scrollTop = bs.scrollTop = sb.scrollTop;
49410 handleScroll : function(e){
49412 var sb = this.scroller.dom;
49413 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
49417 handleWheel : function(e){
49418 var d = e.getWheelDelta();
49419 this.scroller.dom.scrollTop -= d*22;
49420 // set this here to prevent jumpy scrolling on large tables
49421 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
49425 renderRows : function(startRow, endRow){
49426 // pull in all the crap needed to render rows
49427 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
49428 var colCount = cm.getColumnCount();
49430 if(ds.getCount() < 1){
49434 // build a map for all the columns
49436 for(var i = 0; i < colCount; i++){
49437 var name = cm.getDataIndex(i);
49439 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
49440 renderer : cm.getRenderer(i),
49441 id : cm.getColumnId(i),
49442 locked : cm.isLocked(i)
49446 startRow = startRow || 0;
49447 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
49449 // records to render
49450 var rs = ds.getRange(startRow, endRow);
49452 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
49455 // As much as I hate to duplicate code, this was branched because FireFox really hates
49456 // [].join("") on strings. The performance difference was substantial enough to
49457 // branch this function
49458 doRender : Roo.isGecko ?
49459 function(cs, rs, ds, startRow, colCount, stripe){
49460 var ts = this.templates, ct = ts.cell, rt = ts.row;
49462 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49464 var hasListener = this.grid.hasListener('rowclass');
49466 for(var j = 0, len = rs.length; j < len; j++){
49467 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
49468 for(var i = 0; i < colCount; i++){
49470 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49472 p.css = p.attr = "";
49473 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49474 if(p.value == undefined || p.value === "") p.value = " ";
49475 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49476 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49478 var markup = ct.apply(p);
49486 if(stripe && ((rowIndex+1) % 2 == 0)){
49487 alt.push("x-grid-row-alt")
49490 alt.push( " x-grid-dirty-row");
49493 if(this.getRowClass){
49494 alt.push(this.getRowClass(r, rowIndex));
49500 rowIndex : rowIndex,
49503 this.grid.fireEvent('rowclass', this, rowcfg);
49504 alt.push(rowcfg.rowClass);
49506 rp.alt = alt.join(" ");
49507 lbuf+= rt.apply(rp);
49509 buf+= rt.apply(rp);
49511 return [lbuf, buf];
49513 function(cs, rs, ds, startRow, colCount, stripe){
49514 var ts = this.templates, ct = ts.cell, rt = ts.row;
49516 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49517 var hasListener = this.grid.hasListener('rowclass');
49520 for(var j = 0, len = rs.length; j < len; j++){
49521 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
49522 for(var i = 0; i < colCount; i++){
49524 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49526 p.css = p.attr = "";
49527 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49528 if(p.value == undefined || p.value === "") p.value = " ";
49529 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49530 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49533 var markup = ct.apply(p);
49535 cb[cb.length] = markup;
49537 lcb[lcb.length] = markup;
49541 if(stripe && ((rowIndex+1) % 2 == 0)){
49542 alt.push( "x-grid-row-alt");
49545 alt.push(" x-grid-dirty-row");
49548 if(this.getRowClass){
49549 alt.push( this.getRowClass(r, rowIndex));
49555 rowIndex : rowIndex,
49558 this.grid.fireEvent('rowclass', this, rowcfg);
49559 alt.push(rowcfg.rowClass);
49561 rp.alt = alt.join(" ");
49562 rp.cells = lcb.join("");
49563 lbuf[lbuf.length] = rt.apply(rp);
49564 rp.cells = cb.join("");
49565 buf[buf.length] = rt.apply(rp);
49567 return [lbuf.join(""), buf.join("")];
49570 renderBody : function(){
49571 var markup = this.renderRows();
49572 var bt = this.templates.body;
49573 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
49577 * Refreshes the grid
49578 * @param {Boolean} headersToo
49580 refresh : function(headersToo){
49581 this.fireEvent("beforerefresh", this);
49582 this.grid.stopEditing();
49583 var result = this.renderBody();
49584 this.lockedBody.update(result[0]);
49585 this.mainBody.update(result[1]);
49586 if(headersToo === true){
49587 this.updateHeaders();
49588 this.updateColumns();
49589 this.updateSplitters();
49590 this.updateHeaderSortState();
49592 this.syncRowHeights();
49594 this.fireEvent("refresh", this);
49597 handleColumnMove : function(cm, oldIndex, newIndex){
49598 this.indexMap = null;
49599 var s = this.getScrollState();
49600 this.refresh(true);
49601 this.restoreScroll(s);
49602 this.afterMove(newIndex);
49605 afterMove : function(colIndex){
49606 if(this.enableMoveAnim && Roo.enableFx){
49607 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
49609 // if multisort - fix sortOrder, and reload..
49610 if (this.grid.dataSource.multiSort) {
49611 // the we can call sort again..
49612 var dm = this.grid.dataSource;
49613 var cm = this.grid.colModel;
49615 for(var i = 0; i < cm.config.length; i++ ) {
49617 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
49618 continue; // dont' bother, it's not in sort list or being set.
49621 so.push(cm.config[i].dataIndex);
49624 dm.load(dm.lastOptions);
49631 updateCell : function(dm, rowIndex, dataIndex){
49632 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
49633 if(typeof colIndex == "undefined"){ // not present in grid
49636 var cm = this.grid.colModel;
49637 var cell = this.getCell(rowIndex, colIndex);
49638 var cellText = this.getCellText(rowIndex, colIndex);
49641 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
49642 id : cm.getColumnId(colIndex),
49643 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
49645 var renderer = cm.getRenderer(colIndex);
49646 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
49647 if(typeof val == "undefined" || val === "") val = " ";
49648 cellText.innerHTML = val;
49649 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
49650 this.syncRowHeights(rowIndex, rowIndex);
49653 calcColumnWidth : function(colIndex, maxRowsToMeasure){
49655 if(this.grid.autoSizeHeaders){
49656 var h = this.getHeaderCellMeasure(colIndex);
49657 maxWidth = Math.max(maxWidth, h.scrollWidth);
49660 if(this.cm.isLocked(colIndex)){
49661 tb = this.getLockedTable();
49664 tb = this.getBodyTable();
49665 index = colIndex - this.cm.getLockedCount();
49668 var rows = tb.rows;
49669 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
49670 for(var i = 0; i < stopIndex; i++){
49671 var cell = rows[i].childNodes[index].firstChild;
49672 maxWidth = Math.max(maxWidth, cell.scrollWidth);
49675 return maxWidth + /*margin for error in IE*/ 5;
49678 * Autofit a column to its content.
49679 * @param {Number} colIndex
49680 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
49682 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
49683 if(this.cm.isHidden(colIndex)){
49684 return; // can't calc a hidden column
49687 var cid = this.cm.getColumnId(colIndex);
49688 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
49689 if(this.grid.autoSizeHeaders){
49690 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
49693 var newWidth = this.calcColumnWidth(colIndex);
49694 this.cm.setColumnWidth(colIndex,
49695 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
49696 if(!suppressEvent){
49697 this.grid.fireEvent("columnresize", colIndex, newWidth);
49702 * Autofits all columns to their content and then expands to fit any extra space in the grid
49704 autoSizeColumns : function(){
49705 var cm = this.grid.colModel;
49706 var colCount = cm.getColumnCount();
49707 for(var i = 0; i < colCount; i++){
49708 this.autoSizeColumn(i, true, true);
49710 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
49713 this.updateColumns();
49719 * Autofits all columns to the grid's width proportionate with their current size
49720 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
49722 fitColumns : function(reserveScrollSpace){
49723 var cm = this.grid.colModel;
49724 var colCount = cm.getColumnCount();
49728 for (i = 0; i < colCount; i++){
49729 if(!cm.isHidden(i) && !cm.isFixed(i)){
49730 w = cm.getColumnWidth(i);
49736 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
49737 if(reserveScrollSpace){
49740 var frac = (avail - cm.getTotalWidth())/width;
49741 while (cols.length){
49744 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
49746 this.updateColumns();
49750 onRowSelect : function(rowIndex){
49751 var row = this.getRowComposite(rowIndex);
49752 row.addClass("x-grid-row-selected");
49755 onRowDeselect : function(rowIndex){
49756 var row = this.getRowComposite(rowIndex);
49757 row.removeClass("x-grid-row-selected");
49760 onCellSelect : function(row, col){
49761 var cell = this.getCell(row, col);
49763 Roo.fly(cell).addClass("x-grid-cell-selected");
49767 onCellDeselect : function(row, col){
49768 var cell = this.getCell(row, col);
49770 Roo.fly(cell).removeClass("x-grid-cell-selected");
49774 updateHeaderSortState : function(){
49776 // sort state can be single { field: xxx, direction : yyy}
49777 // or { xxx=>ASC , yyy : DESC ..... }
49780 if (!this.ds.multiSort) {
49781 var state = this.ds.getSortState();
49785 mstate[state.field] = state.direction;
49786 // FIXME... - this is not used here.. but might be elsewhere..
49787 this.sortState = state;
49790 mstate = this.ds.sortToggle;
49792 //remove existing sort classes..
49794 var sc = this.sortClasses;
49795 var hds = this.el.select(this.headerSelector).removeClass(sc);
49797 for(var f in mstate) {
49799 var sortColumn = this.cm.findColumnIndex(f);
49801 if(sortColumn != -1){
49802 var sortDir = mstate[f];
49803 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
49812 handleHeaderClick : function(g, index){
49813 if(this.headersDisabled){
49816 var dm = g.dataSource, cm = g.colModel;
49817 if(!cm.isSortable(index)){
49822 if (dm.multiSort) {
49823 // update the sortOrder
49825 for(var i = 0; i < cm.config.length; i++ ) {
49827 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
49828 continue; // dont' bother, it's not in sort list or being set.
49831 so.push(cm.config[i].dataIndex);
49837 dm.sort(cm.getDataIndex(index));
49841 destroy : function(){
49843 this.colMenu.removeAll();
49844 Roo.menu.MenuMgr.unregister(this.colMenu);
49845 this.colMenu.getEl().remove();
49846 delete this.colMenu;
49849 this.hmenu.removeAll();
49850 Roo.menu.MenuMgr.unregister(this.hmenu);
49851 this.hmenu.getEl().remove();
49854 if(this.grid.enableColumnMove){
49855 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49857 for(var dd in dds){
49858 if(!dds[dd].config.isTarget && dds[dd].dragElId){
49859 var elid = dds[dd].dragElId;
49861 Roo.get(elid).remove();
49862 } else if(dds[dd].config.isTarget){
49863 dds[dd].proxyTop.remove();
49864 dds[dd].proxyBottom.remove();
49867 if(Roo.dd.DDM.locationCache[dd]){
49868 delete Roo.dd.DDM.locationCache[dd];
49871 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49874 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
49875 this.bind(null, null);
49876 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
49879 handleLockChange : function(){
49880 this.refresh(true);
49883 onDenyColumnLock : function(){
49887 onDenyColumnHide : function(){
49891 handleHdMenuClick : function(item){
49892 var index = this.hdCtxIndex;
49893 var cm = this.cm, ds = this.ds;
49896 ds.sort(cm.getDataIndex(index), "ASC");
49899 ds.sort(cm.getDataIndex(index), "DESC");
49902 var lc = cm.getLockedCount();
49903 if(cm.getColumnCount(true) <= lc+1){
49904 this.onDenyColumnLock();
49908 cm.setLocked(index, true, true);
49909 cm.moveColumn(index, lc);
49910 this.grid.fireEvent("columnmove", index, lc);
49912 cm.setLocked(index, true);
49916 var lc = cm.getLockedCount();
49917 if((lc-1) != index){
49918 cm.setLocked(index, false, true);
49919 cm.moveColumn(index, lc-1);
49920 this.grid.fireEvent("columnmove", index, lc-1);
49922 cm.setLocked(index, false);
49926 index = cm.getIndexById(item.id.substr(4));
49928 if(item.checked && cm.getColumnCount(true) <= 1){
49929 this.onDenyColumnHide();
49932 cm.setHidden(index, item.checked);
49938 beforeColMenuShow : function(){
49939 var cm = this.cm, colCount = cm.getColumnCount();
49940 this.colMenu.removeAll();
49941 for(var i = 0; i < colCount; i++){
49942 this.colMenu.add(new Roo.menu.CheckItem({
49943 id: "col-"+cm.getColumnId(i),
49944 text: cm.getColumnHeader(i),
49945 checked: !cm.isHidden(i),
49951 handleHdCtx : function(g, index, e){
49953 var hd = this.getHeaderCell(index);
49954 this.hdCtxIndex = index;
49955 var ms = this.hmenu.items, cm = this.cm;
49956 ms.get("asc").setDisabled(!cm.isSortable(index));
49957 ms.get("desc").setDisabled(!cm.isSortable(index));
49958 if(this.grid.enableColLock !== false){
49959 ms.get("lock").setDisabled(cm.isLocked(index));
49960 ms.get("unlock").setDisabled(!cm.isLocked(index));
49962 this.hmenu.show(hd, "tl-bl");
49965 handleHdOver : function(e){
49966 var hd = this.findHeaderCell(e.getTarget());
49967 if(hd && !this.headersDisabled){
49968 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
49969 this.fly(hd).addClass("x-grid-hd-over");
49974 handleHdOut : function(e){
49975 var hd = this.findHeaderCell(e.getTarget());
49977 this.fly(hd).removeClass("x-grid-hd-over");
49981 handleSplitDblClick : function(e, t){
49982 var i = this.getCellIndex(t);
49983 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
49984 this.autoSizeColumn(i, true);
49989 render : function(){
49992 var colCount = cm.getColumnCount();
49994 if(this.grid.monitorWindowResize === true){
49995 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49997 var header = this.renderHeaders();
49998 var body = this.templates.body.apply({rows:""});
49999 var html = this.templates.master.apply({
50002 lockedHeader: header[0],
50006 //this.updateColumns();
50008 this.grid.getGridEl().dom.innerHTML = html;
50010 this.initElements();
50012 // a kludge to fix the random scolling effect in webkit
50013 this.el.on("scroll", function() {
50014 this.el.dom.scrollTop=0; // hopefully not recursive..
50017 this.scroller.on("scroll", this.handleScroll, this);
50018 this.lockedBody.on("mousewheel", this.handleWheel, this);
50019 this.mainBody.on("mousewheel", this.handleWheel, this);
50021 this.mainHd.on("mouseover", this.handleHdOver, this);
50022 this.mainHd.on("mouseout", this.handleHdOut, this);
50023 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
50024 {delegate: "."+this.splitClass});
50026 this.lockedHd.on("mouseover", this.handleHdOver, this);
50027 this.lockedHd.on("mouseout", this.handleHdOut, this);
50028 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
50029 {delegate: "."+this.splitClass});
50031 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
50032 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50035 this.updateSplitters();
50037 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
50038 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50039 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50042 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
50043 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
50045 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
50046 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
50048 if(this.grid.enableColLock !== false){
50049 this.hmenu.add('-',
50050 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
50051 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
50054 if(this.grid.enableColumnHide !== false){
50056 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
50057 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
50058 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
50060 this.hmenu.add('-',
50061 {id:"columns", text: this.columnsText, menu: this.colMenu}
50064 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
50066 this.grid.on("headercontextmenu", this.handleHdCtx, this);
50069 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
50070 this.dd = new Roo.grid.GridDragZone(this.grid, {
50071 ddGroup : this.grid.ddGroup || 'GridDD'
50076 for(var i = 0; i < colCount; i++){
50077 if(cm.isHidden(i)){
50078 this.hideColumn(i);
50080 if(cm.config[i].align){
50081 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
50082 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
50086 this.updateHeaderSortState();
50088 this.beforeInitialResize();
50091 // two part rendering gives faster view to the user
50092 this.renderPhase2.defer(1, this);
50095 renderPhase2 : function(){
50096 // render the rows now
50098 if(this.grid.autoSizeColumns){
50099 this.autoSizeColumns();
50103 beforeInitialResize : function(){
50107 onColumnSplitterMoved : function(i, w){
50108 this.userResized = true;
50109 var cm = this.grid.colModel;
50110 cm.setColumnWidth(i, w, true);
50111 var cid = cm.getColumnId(i);
50112 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
50113 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
50114 this.updateSplitters();
50116 this.grid.fireEvent("columnresize", i, w);
50119 syncRowHeights : function(startIndex, endIndex){
50120 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
50121 startIndex = startIndex || 0;
50122 var mrows = this.getBodyTable().rows;
50123 var lrows = this.getLockedTable().rows;
50124 var len = mrows.length-1;
50125 endIndex = Math.min(endIndex || len, len);
50126 for(var i = startIndex; i <= endIndex; i++){
50127 var m = mrows[i], l = lrows[i];
50128 var h = Math.max(m.offsetHeight, l.offsetHeight);
50129 m.style.height = l.style.height = h + "px";
50134 layout : function(initialRender, is2ndPass){
50136 var auto = g.autoHeight;
50137 var scrollOffset = 16;
50138 var c = g.getGridEl(), cm = this.cm,
50139 expandCol = g.autoExpandColumn,
50141 //c.beginMeasure();
50143 if(!c.dom.offsetWidth){ // display:none?
50145 this.lockedWrap.show();
50146 this.mainWrap.show();
50151 var hasLock = this.cm.isLocked(0);
50153 var tbh = this.headerPanel.getHeight();
50154 var bbh = this.footerPanel.getHeight();
50157 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
50158 var newHeight = ch + c.getBorderWidth("tb");
50160 newHeight = Math.min(g.maxHeight, newHeight);
50162 c.setHeight(newHeight);
50166 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
50169 var s = this.scroller;
50171 var csize = c.getSize(true);
50173 this.el.setSize(csize.width, csize.height);
50175 this.headerPanel.setWidth(csize.width);
50176 this.footerPanel.setWidth(csize.width);
50178 var hdHeight = this.mainHd.getHeight();
50179 var vw = csize.width;
50180 var vh = csize.height - (tbh + bbh);
50184 var bt = this.getBodyTable();
50185 var ltWidth = hasLock ?
50186 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
50188 var scrollHeight = bt.offsetHeight;
50189 var scrollWidth = ltWidth + bt.offsetWidth;
50190 var vscroll = false, hscroll = false;
50192 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
50194 var lw = this.lockedWrap, mw = this.mainWrap;
50195 var lb = this.lockedBody, mb = this.mainBody;
50197 setTimeout(function(){
50198 var t = s.dom.offsetTop;
50199 var w = s.dom.clientWidth,
50200 h = s.dom.clientHeight;
50203 lw.setSize(ltWidth, h);
50205 mw.setLeftTop(ltWidth, t);
50206 mw.setSize(w-ltWidth, h);
50208 lb.setHeight(h-hdHeight);
50209 mb.setHeight(h-hdHeight);
50211 if(is2ndPass !== true && !gv.userResized && expandCol){
50212 // high speed resize without full column calculation
50214 var ci = cm.getIndexById(expandCol);
50216 ci = cm.findColumnIndex(expandCol);
50218 ci = Math.max(0, ci); // make sure it's got at least the first col.
50219 var expandId = cm.getColumnId(ci);
50220 var tw = cm.getTotalWidth(false);
50221 var currentWidth = cm.getColumnWidth(ci);
50222 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
50223 if(currentWidth != cw){
50224 cm.setColumnWidth(ci, cw, true);
50225 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
50226 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
50227 gv.updateSplitters();
50228 gv.layout(false, true);
50240 onWindowResize : function(){
50241 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
50247 appendFooter : function(parentEl){
50251 sortAscText : "Sort Ascending",
50252 sortDescText : "Sort Descending",
50253 lockText : "Lock Column",
50254 unlockText : "Unlock Column",
50255 columnsText : "Columns"
50259 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
50260 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
50261 this.proxy.el.addClass('x-grid3-col-dd');
50264 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
50265 handleMouseDown : function(e){
50269 callHandleMouseDown : function(e){
50270 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
50275 * Ext JS Library 1.1.1
50276 * Copyright(c) 2006-2007, Ext JS, LLC.
50278 * Originally Released Under LGPL - original licence link has changed is not relivant.
50281 * <script type="text/javascript">
50285 // This is a support class used internally by the Grid components
50286 Roo.grid.SplitDragZone = function(grid, hd, hd2){
50288 this.view = grid.getView();
50289 this.proxy = this.view.resizeProxy;
50290 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
50291 "gridSplitters" + this.grid.getGridEl().id, {
50292 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
50294 this.setHandleElId(Roo.id(hd));
50295 this.setOuterHandleElId(Roo.id(hd2));
50296 this.scroll = false;
50298 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
50299 fly: Roo.Element.fly,
50301 b4StartDrag : function(x, y){
50302 this.view.headersDisabled = true;
50303 this.proxy.setHeight(this.view.mainWrap.getHeight());
50304 var w = this.cm.getColumnWidth(this.cellIndex);
50305 var minw = Math.max(w-this.grid.minColumnWidth, 0);
50306 this.resetConstraints();
50307 this.setXConstraint(minw, 1000);
50308 this.setYConstraint(0, 0);
50309 this.minX = x - minw;
50310 this.maxX = x + 1000;
50312 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
50316 handleMouseDown : function(e){
50317 ev = Roo.EventObject.setEvent(e);
50318 var t = this.fly(ev.getTarget());
50319 if(t.hasClass("x-grid-split")){
50320 this.cellIndex = this.view.getCellIndex(t.dom);
50321 this.split = t.dom;
50322 this.cm = this.grid.colModel;
50323 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
50324 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
50329 endDrag : function(e){
50330 this.view.headersDisabled = false;
50331 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
50332 var diff = endX - this.startPos;
50333 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
50336 autoOffset : function(){
50337 this.setDelta(0,0);
50341 * Ext JS Library 1.1.1
50342 * Copyright(c) 2006-2007, Ext JS, LLC.
50344 * Originally Released Under LGPL - original licence link has changed is not relivant.
50347 * <script type="text/javascript">
50351 // This is a support class used internally by the Grid components
50352 Roo.grid.GridDragZone = function(grid, config){
50353 this.view = grid.getView();
50354 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
50355 if(this.view.lockedBody){
50356 this.setHandleElId(Roo.id(this.view.mainBody.dom));
50357 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
50359 this.scroll = false;
50361 this.ddel = document.createElement('div');
50362 this.ddel.className = 'x-grid-dd-wrap';
50365 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
50366 ddGroup : "GridDD",
50368 getDragData : function(e){
50369 var t = Roo.lib.Event.getTarget(e);
50370 var rowIndex = this.view.findRowIndex(t);
50371 if(rowIndex !== false){
50372 var sm = this.grid.selModel;
50373 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
50374 // sm.mouseDown(e, t);
50376 if (e.hasModifier()){
50377 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
50379 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
50384 onInitDrag : function(e){
50385 var data = this.dragData;
50386 this.ddel.innerHTML = this.grid.getDragDropText();
50387 this.proxy.update(this.ddel);
50388 // fire start drag?
50391 afterRepair : function(){
50392 this.dragging = false;
50395 getRepairXY : function(e, data){
50399 onEndDrag : function(data, e){
50403 onValidDrop : function(dd, e, id){
50408 beforeInvalidDrop : function(e, id){
50413 * Ext JS Library 1.1.1
50414 * Copyright(c) 2006-2007, Ext JS, LLC.
50416 * Originally Released Under LGPL - original licence link has changed is not relivant.
50419 * <script type="text/javascript">
50424 * @class Roo.grid.ColumnModel
50425 * @extends Roo.util.Observable
50426 * This is the default implementation of a ColumnModel used by the Grid. It defines
50427 * the columns in the grid.
50430 var colModel = new Roo.grid.ColumnModel([
50431 {header: "Ticker", width: 60, sortable: true, locked: true},
50432 {header: "Company Name", width: 150, sortable: true},
50433 {header: "Market Cap.", width: 100, sortable: true},
50434 {header: "$ Sales", width: 100, sortable: true, renderer: money},
50435 {header: "Employees", width: 100, sortable: true, resizable: false}
50440 * The config options listed for this class are options which may appear in each
50441 * individual column definition.
50442 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
50444 * @param {Object} config An Array of column config objects. See this class's
50445 * config objects for details.
50447 Roo.grid.ColumnModel = function(config){
50449 * The config passed into the constructor
50451 this.config = config;
50454 // if no id, create one
50455 // if the column does not have a dataIndex mapping,
50456 // map it to the order it is in the config
50457 for(var i = 0, len = config.length; i < len; i++){
50459 if(typeof c.dataIndex == "undefined"){
50462 if(typeof c.renderer == "string"){
50463 c.renderer = Roo.util.Format[c.renderer];
50465 if(typeof c.id == "undefined"){
50468 if(c.editor && c.editor.xtype){
50469 c.editor = Roo.factory(c.editor, Roo.grid);
50471 if(c.editor && c.editor.isFormField){
50472 c.editor = new Roo.grid.GridEditor(c.editor);
50474 this.lookup[c.id] = c;
50478 * The width of columns which have no width specified (defaults to 100)
50481 this.defaultWidth = 100;
50484 * Default sortable of columns which have no sortable specified (defaults to false)
50487 this.defaultSortable = false;
50491 * @event widthchange
50492 * Fires when the width of a column changes.
50493 * @param {ColumnModel} this
50494 * @param {Number} columnIndex The column index
50495 * @param {Number} newWidth The new width
50497 "widthchange": true,
50499 * @event headerchange
50500 * Fires when the text of a header changes.
50501 * @param {ColumnModel} this
50502 * @param {Number} columnIndex The column index
50503 * @param {Number} newText The new header text
50505 "headerchange": true,
50507 * @event hiddenchange
50508 * Fires when a column is hidden or "unhidden".
50509 * @param {ColumnModel} this
50510 * @param {Number} columnIndex The column index
50511 * @param {Boolean} hidden true if hidden, false otherwise
50513 "hiddenchange": true,
50515 * @event columnmoved
50516 * Fires when a column is moved.
50517 * @param {ColumnModel} this
50518 * @param {Number} oldIndex
50519 * @param {Number} newIndex
50521 "columnmoved" : true,
50523 * @event columlockchange
50524 * Fires when a column's locked state is changed
50525 * @param {ColumnModel} this
50526 * @param {Number} colIndex
50527 * @param {Boolean} locked true if locked
50529 "columnlockchange" : true
50531 Roo.grid.ColumnModel.superclass.constructor.call(this);
50533 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
50535 * @cfg {String} header The header text to display in the Grid view.
50538 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
50539 * {@link Roo.data.Record} definition from which to draw the column's value. If not
50540 * specified, the column's index is used as an index into the Record's data Array.
50543 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
50544 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
50547 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
50548 * Defaults to the value of the {@link #defaultSortable} property.
50549 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
50552 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
50555 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
50558 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
50561 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
50564 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
50565 * given the cell's data value. See {@link #setRenderer}. If not specified, the
50566 * default renderer uses the raw data value.
50569 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
50572 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
50576 * Returns the id of the column at the specified index.
50577 * @param {Number} index The column index
50578 * @return {String} the id
50580 getColumnId : function(index){
50581 return this.config[index].id;
50585 * Returns the column for a specified id.
50586 * @param {String} id The column id
50587 * @return {Object} the column
50589 getColumnById : function(id){
50590 return this.lookup[id];
50595 * Returns the column for a specified dataIndex.
50596 * @param {String} dataIndex The column dataIndex
50597 * @return {Object|Boolean} the column or false if not found
50599 getColumnByDataIndex: function(dataIndex){
50600 var index = this.findColumnIndex(dataIndex);
50601 return index > -1 ? this.config[index] : false;
50605 * Returns the index for a specified column id.
50606 * @param {String} id The column id
50607 * @return {Number} the index, or -1 if not found
50609 getIndexById : function(id){
50610 for(var i = 0, len = this.config.length; i < len; i++){
50611 if(this.config[i].id == id){
50619 * Returns the index for a specified column dataIndex.
50620 * @param {String} dataIndex The column dataIndex
50621 * @return {Number} the index, or -1 if not found
50624 findColumnIndex : function(dataIndex){
50625 for(var i = 0, len = this.config.length; i < len; i++){
50626 if(this.config[i].dataIndex == dataIndex){
50634 moveColumn : function(oldIndex, newIndex){
50635 var c = this.config[oldIndex];
50636 this.config.splice(oldIndex, 1);
50637 this.config.splice(newIndex, 0, c);
50638 this.dataMap = null;
50639 this.fireEvent("columnmoved", this, oldIndex, newIndex);
50642 isLocked : function(colIndex){
50643 return this.config[colIndex].locked === true;
50646 setLocked : function(colIndex, value, suppressEvent){
50647 if(this.isLocked(colIndex) == value){
50650 this.config[colIndex].locked = value;
50651 if(!suppressEvent){
50652 this.fireEvent("columnlockchange", this, colIndex, value);
50656 getTotalLockedWidth : function(){
50657 var totalWidth = 0;
50658 for(var i = 0; i < this.config.length; i++){
50659 if(this.isLocked(i) && !this.isHidden(i)){
50660 this.totalWidth += this.getColumnWidth(i);
50666 getLockedCount : function(){
50667 for(var i = 0, len = this.config.length; i < len; i++){
50668 if(!this.isLocked(i)){
50675 * Returns the number of columns.
50678 getColumnCount : function(visibleOnly){
50679 if(visibleOnly === true){
50681 for(var i = 0, len = this.config.length; i < len; i++){
50682 if(!this.isHidden(i)){
50688 return this.config.length;
50692 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
50693 * @param {Function} fn
50694 * @param {Object} scope (optional)
50695 * @return {Array} result
50697 getColumnsBy : function(fn, scope){
50699 for(var i = 0, len = this.config.length; i < len; i++){
50700 var c = this.config[i];
50701 if(fn.call(scope||this, c, i) === true){
50709 * Returns true if the specified column is sortable.
50710 * @param {Number} col The column index
50711 * @return {Boolean}
50713 isSortable : function(col){
50714 if(typeof this.config[col].sortable == "undefined"){
50715 return this.defaultSortable;
50717 return this.config[col].sortable;
50721 * Returns the rendering (formatting) function defined for the column.
50722 * @param {Number} col The column index.
50723 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
50725 getRenderer : function(col){
50726 if(!this.config[col].renderer){
50727 return Roo.grid.ColumnModel.defaultRenderer;
50729 return this.config[col].renderer;
50733 * Sets the rendering (formatting) function for a column.
50734 * @param {Number} col The column index
50735 * @param {Function} fn The function to use to process the cell's raw data
50736 * to return HTML markup for the grid view. The render function is called with
50737 * the following parameters:<ul>
50738 * <li>Data value.</li>
50739 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
50740 * <li>css A CSS style string to apply to the table cell.</li>
50741 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
50742 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
50743 * <li>Row index</li>
50744 * <li>Column index</li>
50745 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
50747 setRenderer : function(col, fn){
50748 this.config[col].renderer = fn;
50752 * Returns the width for the specified column.
50753 * @param {Number} col The column index
50756 getColumnWidth : function(col){
50757 return this.config[col].width * 1 || this.defaultWidth;
50761 * Sets the width for a column.
50762 * @param {Number} col The column index
50763 * @param {Number} width The new width
50765 setColumnWidth : function(col, width, suppressEvent){
50766 this.config[col].width = width;
50767 this.totalWidth = null;
50768 if(!suppressEvent){
50769 this.fireEvent("widthchange", this, col, width);
50774 * Returns the total width of all columns.
50775 * @param {Boolean} includeHidden True to include hidden column widths
50778 getTotalWidth : function(includeHidden){
50779 if(!this.totalWidth){
50780 this.totalWidth = 0;
50781 for(var i = 0, len = this.config.length; i < len; i++){
50782 if(includeHidden || !this.isHidden(i)){
50783 this.totalWidth += this.getColumnWidth(i);
50787 return this.totalWidth;
50791 * Returns the header for the specified column.
50792 * @param {Number} col The column index
50795 getColumnHeader : function(col){
50796 return this.config[col].header;
50800 * Sets the header for a column.
50801 * @param {Number} col The column index
50802 * @param {String} header The new header
50804 setColumnHeader : function(col, header){
50805 this.config[col].header = header;
50806 this.fireEvent("headerchange", this, col, header);
50810 * Returns the tooltip for the specified column.
50811 * @param {Number} col The column index
50814 getColumnTooltip : function(col){
50815 return this.config[col].tooltip;
50818 * Sets the tooltip for a column.
50819 * @param {Number} col The column index
50820 * @param {String} tooltip The new tooltip
50822 setColumnTooltip : function(col, tooltip){
50823 this.config[col].tooltip = tooltip;
50827 * Returns the dataIndex for the specified column.
50828 * @param {Number} col The column index
50831 getDataIndex : function(col){
50832 return this.config[col].dataIndex;
50836 * Sets the dataIndex for a column.
50837 * @param {Number} col The column index
50838 * @param {Number} dataIndex The new dataIndex
50840 setDataIndex : function(col, dataIndex){
50841 this.config[col].dataIndex = dataIndex;
50847 * Returns true if the cell is editable.
50848 * @param {Number} colIndex The column index
50849 * @param {Number} rowIndex The row index
50850 * @return {Boolean}
50852 isCellEditable : function(colIndex, rowIndex){
50853 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
50857 * Returns the editor defined for the cell/column.
50858 * return false or null to disable editing.
50859 * @param {Number} colIndex The column index
50860 * @param {Number} rowIndex The row index
50863 getCellEditor : function(colIndex, rowIndex){
50864 return this.config[colIndex].editor;
50868 * Sets if a column is editable.
50869 * @param {Number} col The column index
50870 * @param {Boolean} editable True if the column is editable
50872 setEditable : function(col, editable){
50873 this.config[col].editable = editable;
50878 * Returns true if the column is hidden.
50879 * @param {Number} colIndex The column index
50880 * @return {Boolean}
50882 isHidden : function(colIndex){
50883 return this.config[colIndex].hidden;
50888 * Returns true if the column width cannot be changed
50890 isFixed : function(colIndex){
50891 return this.config[colIndex].fixed;
50895 * Returns true if the column can be resized
50896 * @return {Boolean}
50898 isResizable : function(colIndex){
50899 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
50902 * Sets if a column is hidden.
50903 * @param {Number} colIndex The column index
50904 * @param {Boolean} hidden True if the column is hidden
50906 setHidden : function(colIndex, hidden){
50907 this.config[colIndex].hidden = hidden;
50908 this.totalWidth = null;
50909 this.fireEvent("hiddenchange", this, colIndex, hidden);
50913 * Sets the editor for a column.
50914 * @param {Number} col The column index
50915 * @param {Object} editor The editor object
50917 setEditor : function(col, editor){
50918 this.config[col].editor = editor;
50922 Roo.grid.ColumnModel.defaultRenderer = function(value){
50923 if(typeof value == "string" && value.length < 1){
50929 // Alias for backwards compatibility
50930 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
50933 * Ext JS Library 1.1.1
50934 * Copyright(c) 2006-2007, Ext JS, LLC.
50936 * Originally Released Under LGPL - original licence link has changed is not relivant.
50939 * <script type="text/javascript">
50943 * @class Roo.grid.AbstractSelectionModel
50944 * @extends Roo.util.Observable
50945 * Abstract base class for grid SelectionModels. It provides the interface that should be
50946 * implemented by descendant classes. This class should not be directly instantiated.
50949 Roo.grid.AbstractSelectionModel = function(){
50950 this.locked = false;
50951 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
50954 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
50955 /** @ignore Called by the grid automatically. Do not call directly. */
50956 init : function(grid){
50962 * Locks the selections.
50965 this.locked = true;
50969 * Unlocks the selections.
50971 unlock : function(){
50972 this.locked = false;
50976 * Returns true if the selections are locked.
50977 * @return {Boolean}
50979 isLocked : function(){
50980 return this.locked;
50984 * Ext JS Library 1.1.1
50985 * Copyright(c) 2006-2007, Ext JS, LLC.
50987 * Originally Released Under LGPL - original licence link has changed is not relivant.
50990 * <script type="text/javascript">
50993 * @extends Roo.grid.AbstractSelectionModel
50994 * @class Roo.grid.RowSelectionModel
50995 * The default SelectionModel used by {@link Roo.grid.Grid}.
50996 * It supports multiple selections and keyboard selection/navigation.
50998 * @param {Object} config
51000 Roo.grid.RowSelectionModel = function(config){
51001 Roo.apply(this, config);
51002 this.selections = new Roo.util.MixedCollection(false, function(o){
51007 this.lastActive = false;
51011 * @event selectionchange
51012 * Fires when the selection changes
51013 * @param {SelectionModel} this
51015 "selectionchange" : true,
51017 * @event afterselectionchange
51018 * Fires after the selection changes (eg. by key press or clicking)
51019 * @param {SelectionModel} this
51021 "afterselectionchange" : true,
51023 * @event beforerowselect
51024 * Fires when a row is selected being selected, return false to cancel.
51025 * @param {SelectionModel} this
51026 * @param {Number} rowIndex The selected index
51027 * @param {Boolean} keepExisting False if other selections will be cleared
51029 "beforerowselect" : true,
51032 * Fires when a row is selected.
51033 * @param {SelectionModel} this
51034 * @param {Number} rowIndex The selected index
51035 * @param {Roo.data.Record} r The record
51037 "rowselect" : true,
51039 * @event rowdeselect
51040 * Fires when a row is deselected.
51041 * @param {SelectionModel} this
51042 * @param {Number} rowIndex The selected index
51044 "rowdeselect" : true
51046 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
51047 this.locked = false;
51050 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
51052 * @cfg {Boolean} singleSelect
51053 * True to allow selection of only one row at a time (defaults to false)
51055 singleSelect : false,
51058 initEvents : function(){
51060 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
51061 this.grid.on("mousedown", this.handleMouseDown, this);
51062 }else{ // allow click to work like normal
51063 this.grid.on("rowclick", this.handleDragableRowClick, this);
51066 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
51067 "up" : function(e){
51069 this.selectPrevious(e.shiftKey);
51070 }else if(this.last !== false && this.lastActive !== false){
51071 var last = this.last;
51072 this.selectRange(this.last, this.lastActive-1);
51073 this.grid.getView().focusRow(this.lastActive);
51074 if(last !== false){
51078 this.selectFirstRow();
51080 this.fireEvent("afterselectionchange", this);
51082 "down" : function(e){
51084 this.selectNext(e.shiftKey);
51085 }else if(this.last !== false && this.lastActive !== false){
51086 var last = this.last;
51087 this.selectRange(this.last, this.lastActive+1);
51088 this.grid.getView().focusRow(this.lastActive);
51089 if(last !== false){
51093 this.selectFirstRow();
51095 this.fireEvent("afterselectionchange", this);
51100 var view = this.grid.view;
51101 view.on("refresh", this.onRefresh, this);
51102 view.on("rowupdated", this.onRowUpdated, this);
51103 view.on("rowremoved", this.onRemove, this);
51107 onRefresh : function(){
51108 var ds = this.grid.dataSource, i, v = this.grid.view;
51109 var s = this.selections;
51110 s.each(function(r){
51111 if((i = ds.indexOfId(r.id)) != -1){
51120 onRemove : function(v, index, r){
51121 this.selections.remove(r);
51125 onRowUpdated : function(v, index, r){
51126 if(this.isSelected(r)){
51127 v.onRowSelect(index);
51133 * @param {Array} records The records to select
51134 * @param {Boolean} keepExisting (optional) True to keep existing selections
51136 selectRecords : function(records, keepExisting){
51138 this.clearSelections();
51140 var ds = this.grid.dataSource;
51141 for(var i = 0, len = records.length; i < len; i++){
51142 this.selectRow(ds.indexOf(records[i]), true);
51147 * Gets the number of selected rows.
51150 getCount : function(){
51151 return this.selections.length;
51155 * Selects the first row in the grid.
51157 selectFirstRow : function(){
51162 * Select the last row.
51163 * @param {Boolean} keepExisting (optional) True to keep existing selections
51165 selectLastRow : function(keepExisting){
51166 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
51170 * Selects the row immediately following the last selected row.
51171 * @param {Boolean} keepExisting (optional) True to keep existing selections
51173 selectNext : function(keepExisting){
51174 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
51175 this.selectRow(this.last+1, keepExisting);
51176 this.grid.getView().focusRow(this.last);
51181 * Selects the row that precedes the last selected row.
51182 * @param {Boolean} keepExisting (optional) True to keep existing selections
51184 selectPrevious : function(keepExisting){
51186 this.selectRow(this.last-1, keepExisting);
51187 this.grid.getView().focusRow(this.last);
51192 * Returns the selected records
51193 * @return {Array} Array of selected records
51195 getSelections : function(){
51196 return [].concat(this.selections.items);
51200 * Returns the first selected record.
51203 getSelected : function(){
51204 return this.selections.itemAt(0);
51209 * Clears all selections.
51211 clearSelections : function(fast){
51212 if(this.locked) return;
51214 var ds = this.grid.dataSource;
51215 var s = this.selections;
51216 s.each(function(r){
51217 this.deselectRow(ds.indexOfId(r.id));
51221 this.selections.clear();
51228 * Selects all rows.
51230 selectAll : function(){
51231 if(this.locked) return;
51232 this.selections.clear();
51233 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
51234 this.selectRow(i, true);
51239 * Returns True if there is a selection.
51240 * @return {Boolean}
51242 hasSelection : function(){
51243 return this.selections.length > 0;
51247 * Returns True if the specified row is selected.
51248 * @param {Number/Record} record The record or index of the record to check
51249 * @return {Boolean}
51251 isSelected : function(index){
51252 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
51253 return (r && this.selections.key(r.id) ? true : false);
51257 * Returns True if the specified record id is selected.
51258 * @param {String} id The id of record to check
51259 * @return {Boolean}
51261 isIdSelected : function(id){
51262 return (this.selections.key(id) ? true : false);
51266 handleMouseDown : function(e, t){
51267 var view = this.grid.getView(), rowIndex;
51268 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
51271 if(e.shiftKey && this.last !== false){
51272 var last = this.last;
51273 this.selectRange(last, rowIndex, e.ctrlKey);
51274 this.last = last; // reset the last
51275 view.focusRow(rowIndex);
51277 var isSelected = this.isSelected(rowIndex);
51278 if(e.button !== 0 && isSelected){
51279 view.focusRow(rowIndex);
51280 }else if(e.ctrlKey && isSelected){
51281 this.deselectRow(rowIndex);
51282 }else if(!isSelected){
51283 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
51284 view.focusRow(rowIndex);
51287 this.fireEvent("afterselectionchange", this);
51290 handleDragableRowClick : function(grid, rowIndex, e)
51292 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
51293 this.selectRow(rowIndex, false);
51294 grid.view.focusRow(rowIndex);
51295 this.fireEvent("afterselectionchange", this);
51300 * Selects multiple rows.
51301 * @param {Array} rows Array of the indexes of the row to select
51302 * @param {Boolean} keepExisting (optional) True to keep existing selections
51304 selectRows : function(rows, keepExisting){
51306 this.clearSelections();
51308 for(var i = 0, len = rows.length; i < len; i++){
51309 this.selectRow(rows[i], true);
51314 * Selects a range of rows. All rows in between startRow and endRow are also selected.
51315 * @param {Number} startRow The index of the first row in the range
51316 * @param {Number} endRow The index of the last row in the range
51317 * @param {Boolean} keepExisting (optional) True to retain existing selections
51319 selectRange : function(startRow, endRow, keepExisting){
51320 if(this.locked) return;
51322 this.clearSelections();
51324 if(startRow <= endRow){
51325 for(var i = startRow; i <= endRow; i++){
51326 this.selectRow(i, true);
51329 for(var i = startRow; i >= endRow; i--){
51330 this.selectRow(i, true);
51336 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
51337 * @param {Number} startRow The index of the first row in the range
51338 * @param {Number} endRow The index of the last row in the range
51340 deselectRange : function(startRow, endRow, preventViewNotify){
51341 if(this.locked) return;
51342 for(var i = startRow; i <= endRow; i++){
51343 this.deselectRow(i, preventViewNotify);
51349 * @param {Number} row The index of the row to select
51350 * @param {Boolean} keepExisting (optional) True to keep existing selections
51352 selectRow : function(index, keepExisting, preventViewNotify){
51353 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
51354 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
51355 if(!keepExisting || this.singleSelect){
51356 this.clearSelections();
51358 var r = this.grid.dataSource.getAt(index);
51359 this.selections.add(r);
51360 this.last = this.lastActive = index;
51361 if(!preventViewNotify){
51362 this.grid.getView().onRowSelect(index);
51364 this.fireEvent("rowselect", this, index, r);
51365 this.fireEvent("selectionchange", this);
51371 * @param {Number} row The index of the row to deselect
51373 deselectRow : function(index, preventViewNotify){
51374 if(this.locked) return;
51375 if(this.last == index){
51378 if(this.lastActive == index){
51379 this.lastActive = false;
51381 var r = this.grid.dataSource.getAt(index);
51382 this.selections.remove(r);
51383 if(!preventViewNotify){
51384 this.grid.getView().onRowDeselect(index);
51386 this.fireEvent("rowdeselect", this, index);
51387 this.fireEvent("selectionchange", this);
51391 restoreLast : function(){
51393 this.last = this._last;
51398 acceptsNav : function(row, col, cm){
51399 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51403 onEditorKey : function(field, e){
51404 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
51409 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51411 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51413 }else if(k == e.ENTER && !e.ctrlKey){
51417 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
51419 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
51421 }else if(k == e.ESC){
51425 g.startEditing(newCell[0], newCell[1]);
51430 * Ext JS Library 1.1.1
51431 * Copyright(c) 2006-2007, Ext JS, LLC.
51433 * Originally Released Under LGPL - original licence link has changed is not relivant.
51436 * <script type="text/javascript">
51439 * @class Roo.grid.CellSelectionModel
51440 * @extends Roo.grid.AbstractSelectionModel
51441 * This class provides the basic implementation for cell selection in a grid.
51443 * @param {Object} config The object containing the configuration of this model.
51444 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
51446 Roo.grid.CellSelectionModel = function(config){
51447 Roo.apply(this, config);
51449 this.selection = null;
51453 * @event beforerowselect
51454 * Fires before a cell is selected.
51455 * @param {SelectionModel} this
51456 * @param {Number} rowIndex The selected row index
51457 * @param {Number} colIndex The selected cell index
51459 "beforecellselect" : true,
51461 * @event cellselect
51462 * Fires when a cell is selected.
51463 * @param {SelectionModel} this
51464 * @param {Number} rowIndex The selected row index
51465 * @param {Number} colIndex The selected cell index
51467 "cellselect" : true,
51469 * @event selectionchange
51470 * Fires when the active selection changes.
51471 * @param {SelectionModel} this
51472 * @param {Object} selection null for no selection or an object (o) with two properties
51474 <li>o.record: the record object for the row the selection is in</li>
51475 <li>o.cell: An array of [rowIndex, columnIndex]</li>
51478 "selectionchange" : true,
51481 * Fires when the tab (or enter) was pressed on the last editable cell
51482 * You can use this to trigger add new row.
51483 * @param {SelectionModel} this
51487 * @event beforeeditnext
51488 * Fires before the next editable sell is made active
51489 * You can use this to skip to another cell or fire the tabend
51490 * if you set cell to false
51491 * @param {Object} eventdata object : { cell : [ row, col ] }
51493 "beforeeditnext" : true
51495 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
51498 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
51500 enter_is_tab: false,
51503 initEvents : function(){
51504 this.grid.on("mousedown", this.handleMouseDown, this);
51505 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
51506 var view = this.grid.view;
51507 view.on("refresh", this.onViewChange, this);
51508 view.on("rowupdated", this.onRowUpdated, this);
51509 view.on("beforerowremoved", this.clearSelections, this);
51510 view.on("beforerowsinserted", this.clearSelections, this);
51511 if(this.grid.isEditor){
51512 this.grid.on("beforeedit", this.beforeEdit, this);
51517 beforeEdit : function(e){
51518 this.select(e.row, e.column, false, true, e.record);
51522 onRowUpdated : function(v, index, r){
51523 if(this.selection && this.selection.record == r){
51524 v.onCellSelect(index, this.selection.cell[1]);
51529 onViewChange : function(){
51530 this.clearSelections(true);
51534 * Returns the currently selected cell,.
51535 * @return {Array} The selected cell (row, column) or null if none selected.
51537 getSelectedCell : function(){
51538 return this.selection ? this.selection.cell : null;
51542 * Clears all selections.
51543 * @param {Boolean} true to prevent the gridview from being notified about the change.
51545 clearSelections : function(preventNotify){
51546 var s = this.selection;
51548 if(preventNotify !== true){
51549 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
51551 this.selection = null;
51552 this.fireEvent("selectionchange", this, null);
51557 * Returns true if there is a selection.
51558 * @return {Boolean}
51560 hasSelection : function(){
51561 return this.selection ? true : false;
51565 handleMouseDown : function(e, t){
51566 var v = this.grid.getView();
51567 if(this.isLocked()){
51570 var row = v.findRowIndex(t);
51571 var cell = v.findCellIndex(t);
51572 if(row !== false && cell !== false){
51573 this.select(row, cell);
51579 * @param {Number} rowIndex
51580 * @param {Number} collIndex
51582 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
51583 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
51584 this.clearSelections();
51585 r = r || this.grid.dataSource.getAt(rowIndex);
51588 cell : [rowIndex, colIndex]
51590 if(!preventViewNotify){
51591 var v = this.grid.getView();
51592 v.onCellSelect(rowIndex, colIndex);
51593 if(preventFocus !== true){
51594 v.focusCell(rowIndex, colIndex);
51597 this.fireEvent("cellselect", this, rowIndex, colIndex);
51598 this.fireEvent("selectionchange", this, this.selection);
51603 isSelectable : function(rowIndex, colIndex, cm){
51604 return !cm.isHidden(colIndex);
51608 handleKeyDown : function(e){
51609 //Roo.log('Cell Sel Model handleKeyDown');
51610 if(!e.isNavKeyPress()){
51613 var g = this.grid, s = this.selection;
51616 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
51618 this.select(cell[0], cell[1]);
51623 var walk = function(row, col, step){
51624 return g.walkCells(row, col, step, sm.isSelectable, sm);
51626 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
51633 // handled by onEditorKey
51634 if (g.isEditor && g.editing) {
51638 newCell = walk(r, c-1, -1);
51640 newCell = walk(r, c+1, 1);
51645 newCell = walk(r+1, c, 1);
51649 newCell = walk(r-1, c, -1);
51653 newCell = walk(r, c+1, 1);
51657 newCell = walk(r, c-1, -1);
51662 if(g.isEditor && !g.editing){
51663 g.startEditing(r, c);
51672 this.select(newCell[0], newCell[1]);
51678 acceptsNav : function(row, col, cm){
51679 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51683 * @param {Number} field (not used) - as it's normally used as a listener
51684 * @param {Number} e - event - fake it by using
51686 * var e = Roo.EventObjectImpl.prototype;
51687 * e.keyCode = e.TAB
51691 onEditorKey : function(field, e){
51693 var k = e.getKey(),
51696 ed = g.activeEditor,
51698 ///Roo.log('onEditorKey' + k);
51701 if (this.enter_is_tab && k == e.ENTER) {
51707 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51709 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51715 } else if(k == e.ENTER && !e.ctrlKey){
51718 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51720 } else if(k == e.ESC){
51725 var ecall = { cell : newCell, forward : forward };
51726 this.fireEvent('beforeeditnext', ecall );
51727 newCell = ecall.cell;
51728 forward = ecall.forward;
51732 //Roo.log('next cell after edit');
51733 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
51734 } else if (forward) {
51735 // tabbed past last
51736 this.fireEvent.defer(100, this, ['tabend',this]);
51741 * Ext JS Library 1.1.1
51742 * Copyright(c) 2006-2007, Ext JS, LLC.
51744 * Originally Released Under LGPL - original licence link has changed is not relivant.
51747 * <script type="text/javascript">
51751 * @class Roo.grid.EditorGrid
51752 * @extends Roo.grid.Grid
51753 * Class for creating and editable grid.
51754 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51755 * The container MUST have some type of size defined for the grid to fill. The container will be
51756 * automatically set to position relative if it isn't already.
51757 * @param {Object} dataSource The data model to bind to
51758 * @param {Object} colModel The column model with info about this grid's columns
51760 Roo.grid.EditorGrid = function(container, config){
51761 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
51762 this.getGridEl().addClass("xedit-grid");
51764 if(!this.selModel){
51765 this.selModel = new Roo.grid.CellSelectionModel();
51768 this.activeEditor = null;
51772 * @event beforeedit
51773 * Fires before cell editing is triggered. The edit event object has the following properties <br />
51774 * <ul style="padding:5px;padding-left:16px;">
51775 * <li>grid - This grid</li>
51776 * <li>record - The record being edited</li>
51777 * <li>field - The field name being edited</li>
51778 * <li>value - The value for the field being edited.</li>
51779 * <li>row - The grid row index</li>
51780 * <li>column - The grid column index</li>
51781 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51783 * @param {Object} e An edit event (see above for description)
51785 "beforeedit" : true,
51788 * Fires after a cell is edited. <br />
51789 * <ul style="padding:5px;padding-left:16px;">
51790 * <li>grid - This grid</li>
51791 * <li>record - The record being edited</li>
51792 * <li>field - The field name being edited</li>
51793 * <li>value - The value being set</li>
51794 * <li>originalValue - The original value for the field, before the edit.</li>
51795 * <li>row - The grid row index</li>
51796 * <li>column - The grid column index</li>
51798 * @param {Object} e An edit event (see above for description)
51800 "afteredit" : true,
51802 * @event validateedit
51803 * Fires after a cell is edited, but before the value is set in the record.
51804 * You can use this to modify the value being set in the field, Return false
51805 * to cancel the change. The edit event object has the following properties <br />
51806 * <ul style="padding:5px;padding-left:16px;">
51807 * <li>editor - This editor</li>
51808 * <li>grid - This grid</li>
51809 * <li>record - The record being edited</li>
51810 * <li>field - The field name being edited</li>
51811 * <li>value - The value being set</li>
51812 * <li>originalValue - The original value for the field, before the edit.</li>
51813 * <li>row - The grid row index</li>
51814 * <li>column - The grid column index</li>
51815 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51817 * @param {Object} e An edit event (see above for description)
51819 "validateedit" : true
51821 this.on("bodyscroll", this.stopEditing, this);
51822 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
51825 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
51827 * @cfg {Number} clicksToEdit
51828 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
51835 trackMouseOver: false, // causes very odd FF errors
51837 onCellDblClick : function(g, row, col){
51838 this.startEditing(row, col);
51841 onEditComplete : function(ed, value, startValue){
51842 this.editing = false;
51843 this.activeEditor = null;
51844 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
51846 var field = this.colModel.getDataIndex(ed.col);
51851 originalValue: startValue,
51858 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
51861 if(String(value) !== String(startValue)){
51863 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
51864 r.set(field, e.value);
51865 // if we are dealing with a combo box..
51866 // then we also set the 'name' colum to be the displayField
51867 if (ed.field.displayField && ed.field.name) {
51868 r.set(ed.field.name, ed.field.el.dom.value);
51871 delete e.cancel; //?? why!!!
51872 this.fireEvent("afteredit", e);
51875 this.fireEvent("afteredit", e); // always fire it!
51877 this.view.focusCell(ed.row, ed.col);
51881 * Starts editing the specified for the specified row/column
51882 * @param {Number} rowIndex
51883 * @param {Number} colIndex
51885 startEditing : function(row, col){
51886 this.stopEditing();
51887 if(this.colModel.isCellEditable(col, row)){
51888 this.view.ensureVisible(row, col, true);
51890 var r = this.dataSource.getAt(row);
51891 var field = this.colModel.getDataIndex(col);
51892 var cell = Roo.get(this.view.getCell(row,col));
51897 value: r.data[field],
51902 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
51903 this.editing = true;
51904 var ed = this.colModel.getCellEditor(col, row);
51910 ed.render(ed.parentEl || document.body);
51916 (function(){ // complex but required for focus issues in safari, ie and opera
51920 ed.on("complete", this.onEditComplete, this, {single: true});
51921 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
51922 this.activeEditor = ed;
51923 var v = r.data[field];
51924 ed.startEdit(this.view.getCell(row, col), v);
51925 // combo's with 'displayField and name set
51926 if (ed.field.displayField && ed.field.name) {
51927 ed.field.el.dom.value = r.data[ed.field.name];
51931 }).defer(50, this);
51937 * Stops any active editing
51939 stopEditing : function(){
51940 if(this.activeEditor){
51941 this.activeEditor.completeEdit();
51943 this.activeEditor = null;
51947 * Ext JS Library 1.1.1
51948 * Copyright(c) 2006-2007, Ext JS, LLC.
51950 * Originally Released Under LGPL - original licence link has changed is not relivant.
51953 * <script type="text/javascript">
51956 // private - not really -- you end up using it !
51957 // This is a support class used internally by the Grid components
51960 * @class Roo.grid.GridEditor
51961 * @extends Roo.Editor
51962 * Class for creating and editable grid elements.
51963 * @param {Object} config any settings (must include field)
51965 Roo.grid.GridEditor = function(field, config){
51966 if (!config && field.field) {
51968 field = Roo.factory(config.field, Roo.form);
51970 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
51971 field.monitorTab = false;
51974 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
51977 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
51980 alignment: "tl-tl",
51983 cls: "x-small-editor x-grid-editor",
51988 * Ext JS Library 1.1.1
51989 * Copyright(c) 2006-2007, Ext JS, LLC.
51991 * Originally Released Under LGPL - original licence link has changed is not relivant.
51994 * <script type="text/javascript">
51999 Roo.grid.PropertyRecord = Roo.data.Record.create([
52000 {name:'name',type:'string'}, 'value'
52004 Roo.grid.PropertyStore = function(grid, source){
52006 this.store = new Roo.data.Store({
52007 recordType : Roo.grid.PropertyRecord
52009 this.store.on('update', this.onUpdate, this);
52011 this.setSource(source);
52013 Roo.grid.PropertyStore.superclass.constructor.call(this);
52018 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
52019 setSource : function(o){
52021 this.store.removeAll();
52024 if(this.isEditableValue(o[k])){
52025 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
52028 this.store.loadRecords({records: data}, {}, true);
52031 onUpdate : function(ds, record, type){
52032 if(type == Roo.data.Record.EDIT){
52033 var v = record.data['value'];
52034 var oldValue = record.modified['value'];
52035 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
52036 this.source[record.id] = v;
52038 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
52045 getProperty : function(row){
52046 return this.store.getAt(row);
52049 isEditableValue: function(val){
52050 if(val && val instanceof Date){
52052 }else if(typeof val == 'object' || typeof val == 'function'){
52058 setValue : function(prop, value){
52059 this.source[prop] = value;
52060 this.store.getById(prop).set('value', value);
52063 getSource : function(){
52064 return this.source;
52068 Roo.grid.PropertyColumnModel = function(grid, store){
52071 g.PropertyColumnModel.superclass.constructor.call(this, [
52072 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
52073 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
52075 this.store = store;
52076 this.bselect = Roo.DomHelper.append(document.body, {
52077 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
52078 {tag: 'option', value: 'true', html: 'true'},
52079 {tag: 'option', value: 'false', html: 'false'}
52082 Roo.id(this.bselect);
52085 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
52086 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
52087 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
52088 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
52089 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
52091 this.renderCellDelegate = this.renderCell.createDelegate(this);
52092 this.renderPropDelegate = this.renderProp.createDelegate(this);
52095 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
52099 valueText : 'Value',
52101 dateFormat : 'm/j/Y',
52104 renderDate : function(dateVal){
52105 return dateVal.dateFormat(this.dateFormat);
52108 renderBool : function(bVal){
52109 return bVal ? 'true' : 'false';
52112 isCellEditable : function(colIndex, rowIndex){
52113 return colIndex == 1;
52116 getRenderer : function(col){
52118 this.renderCellDelegate : this.renderPropDelegate;
52121 renderProp : function(v){
52122 return this.getPropertyName(v);
52125 renderCell : function(val){
52127 if(val instanceof Date){
52128 rv = this.renderDate(val);
52129 }else if(typeof val == 'boolean'){
52130 rv = this.renderBool(val);
52132 return Roo.util.Format.htmlEncode(rv);
52135 getPropertyName : function(name){
52136 var pn = this.grid.propertyNames;
52137 return pn && pn[name] ? pn[name] : name;
52140 getCellEditor : function(colIndex, rowIndex){
52141 var p = this.store.getProperty(rowIndex);
52142 var n = p.data['name'], val = p.data['value'];
52144 if(typeof(this.grid.customEditors[n]) == 'string'){
52145 return this.editors[this.grid.customEditors[n]];
52147 if(typeof(this.grid.customEditors[n]) != 'undefined'){
52148 return this.grid.customEditors[n];
52150 if(val instanceof Date){
52151 return this.editors['date'];
52152 }else if(typeof val == 'number'){
52153 return this.editors['number'];
52154 }else if(typeof val == 'boolean'){
52155 return this.editors['boolean'];
52157 return this.editors['string'];
52163 * @class Roo.grid.PropertyGrid
52164 * @extends Roo.grid.EditorGrid
52165 * This class represents the interface of a component based property grid control.
52166 * <br><br>Usage:<pre><code>
52167 var grid = new Roo.grid.PropertyGrid("my-container-id", {
52175 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52176 * The container MUST have some type of size defined for the grid to fill. The container will be
52177 * automatically set to position relative if it isn't already.
52178 * @param {Object} config A config object that sets properties on this grid.
52180 Roo.grid.PropertyGrid = function(container, config){
52181 config = config || {};
52182 var store = new Roo.grid.PropertyStore(this);
52183 this.store = store;
52184 var cm = new Roo.grid.PropertyColumnModel(this, store);
52185 store.store.sort('name', 'ASC');
52186 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
52189 enableColLock:false,
52190 enableColumnMove:false,
52192 trackMouseOver: false,
52195 this.getGridEl().addClass('x-props-grid');
52196 this.lastEditRow = null;
52197 this.on('columnresize', this.onColumnResize, this);
52200 * @event beforepropertychange
52201 * Fires before a property changes (return false to stop?)
52202 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
52203 * @param {String} id Record Id
52204 * @param {String} newval New Value
52205 * @param {String} oldval Old Value
52207 "beforepropertychange": true,
52209 * @event propertychange
52210 * Fires after a property changes
52211 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
52212 * @param {String} id Record Id
52213 * @param {String} newval New Value
52214 * @param {String} oldval Old Value
52216 "propertychange": true
52218 this.customEditors = this.customEditors || {};
52220 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
52223 * @cfg {Object} customEditors map of colnames=> custom editors.
52224 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
52225 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
52226 * false disables editing of the field.
52230 * @cfg {Object} propertyNames map of property Names to their displayed value
52233 render : function(){
52234 Roo.grid.PropertyGrid.superclass.render.call(this);
52235 this.autoSize.defer(100, this);
52238 autoSize : function(){
52239 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
52241 this.view.fitColumns();
52245 onColumnResize : function(){
52246 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
52250 * Sets the data for the Grid
52251 * accepts a Key => Value object of all the elements avaiable.
52252 * @param {Object} data to appear in grid.
52254 setSource : function(source){
52255 this.store.setSource(source);
52259 * Gets all the data from the grid.
52260 * @return {Object} data data stored in grid
52262 getSource : function(){
52263 return this.store.getSource();
52267 * Ext JS Library 1.1.1
52268 * Copyright(c) 2006-2007, Ext JS, LLC.
52270 * Originally Released Under LGPL - original licence link has changed is not relivant.
52273 * <script type="text/javascript">
52277 * @class Roo.LoadMask
52278 * A simple utility class for generically masking elements while loading data. If the element being masked has
52279 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
52280 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
52281 * element's UpdateManager load indicator and will be destroyed after the initial load.
52283 * Create a new LoadMask
52284 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
52285 * @param {Object} config The config object
52287 Roo.LoadMask = function(el, config){
52288 this.el = Roo.get(el);
52289 Roo.apply(this, config);
52291 this.store.on('beforeload', this.onBeforeLoad, this);
52292 this.store.on('load', this.onLoad, this);
52293 this.store.on('loadexception', this.onLoadException, this);
52294 this.removeMask = false;
52296 var um = this.el.getUpdateManager();
52297 um.showLoadIndicator = false; // disable the default indicator
52298 um.on('beforeupdate', this.onBeforeLoad, this);
52299 um.on('update', this.onLoad, this);
52300 um.on('failure', this.onLoad, this);
52301 this.removeMask = true;
52305 Roo.LoadMask.prototype = {
52307 * @cfg {Boolean} removeMask
52308 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
52309 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
52312 * @cfg {String} msg
52313 * The text to display in a centered loading message box (defaults to 'Loading...')
52315 msg : 'Loading...',
52317 * @cfg {String} msgCls
52318 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
52320 msgCls : 'x-mask-loading',
52323 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
52329 * Disables the mask to prevent it from being displayed
52331 disable : function(){
52332 this.disabled = true;
52336 * Enables the mask so that it can be displayed
52338 enable : function(){
52339 this.disabled = false;
52342 onLoadException : function()
52344 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52345 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52347 this.el.unmask(this.removeMask);
52350 onLoad : function()
52352 this.el.unmask(this.removeMask);
52356 onBeforeLoad : function(){
52357 if(!this.disabled){
52358 this.el.mask(this.msg, this.msgCls);
52363 destroy : function(){
52365 this.store.un('beforeload', this.onBeforeLoad, this);
52366 this.store.un('load', this.onLoad, this);
52367 this.store.un('loadexception', this.onLoadException, this);
52369 var um = this.el.getUpdateManager();
52370 um.un('beforeupdate', this.onBeforeLoad, this);
52371 um.un('update', this.onLoad, this);
52372 um.un('failure', this.onLoad, this);
52377 * Ext JS Library 1.1.1
52378 * Copyright(c) 2006-2007, Ext JS, LLC.
52380 * Originally Released Under LGPL - original licence link has changed is not relivant.
52383 * <script type="text/javascript">
52388 * @class Roo.XTemplate
52389 * @extends Roo.Template
52390 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
52392 var t = new Roo.XTemplate(
52393 '<select name="{name}">',
52394 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
52398 // then append, applying the master template values
52401 * Supported features:
52406 {a_variable} - output encoded.
52407 {a_variable.format:("Y-m-d")} - call a method on the variable
52408 {a_variable:raw} - unencoded output
52409 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
52410 {a_variable:this.method_on_template(...)} - call a method on the template object.
52415 <tpl for="a_variable or condition.."></tpl>
52416 <tpl if="a_variable or condition"></tpl>
52417 <tpl exec="some javascript"></tpl>
52418 <tpl name="named_template"></tpl> (experimental)
52420 <tpl for="."></tpl> - just iterate the property..
52421 <tpl for=".."></tpl> - iterates with the parent (probably the template)
52425 Roo.XTemplate = function()
52427 Roo.XTemplate.superclass.constructor.apply(this, arguments);
52434 Roo.extend(Roo.XTemplate, Roo.Template, {
52437 * The various sub templates
52442 * basic tag replacing syntax
52445 * // you can fake an object call by doing this
52449 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
52452 * compile the template
52454 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
52457 compile: function()
52461 s = ['<tpl>', s, '</tpl>'].join('');
52463 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
52464 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
52465 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
52466 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
52467 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
52472 while(true == !!(m = s.match(re))){
52473 var forMatch = m[0].match(nameRe),
52474 ifMatch = m[0].match(ifRe),
52475 execMatch = m[0].match(execRe),
52476 namedMatch = m[0].match(namedRe),
52481 name = forMatch && forMatch[1] ? forMatch[1] : '';
52484 // if - puts fn into test..
52485 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
52487 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
52492 // exec - calls a function... returns empty if true is returned.
52493 exp = execMatch && execMatch[1] ? execMatch[1] : null;
52495 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
52503 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
52504 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
52505 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
52508 var uid = namedMatch ? namedMatch[1] : id;
52512 id: namedMatch ? namedMatch[1] : id,
52519 s = s.replace(m[0], '');
52521 s = s.replace(m[0], '{xtpl'+ id + '}');
52526 for(var i = tpls.length-1; i >= 0; --i){
52527 this.compileTpl(tpls[i]);
52528 this.tpls[tpls[i].id] = tpls[i];
52530 this.master = tpls[tpls.length-1];
52534 * same as applyTemplate, except it's done to one of the subTemplates
52535 * when using named templates, you can do:
52537 * var str = pl.applySubTemplate('your-name', values);
52540 * @param {Number} id of the template
52541 * @param {Object} values to apply to template
52542 * @param {Object} parent (normaly the instance of this object)
52544 applySubTemplate : function(id, values, parent)
52548 var t = this.tpls[id];
52552 if(t.test && !t.test.call(this, values, parent)){
52556 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
52557 Roo.log(e.toString());
52563 if(t.exec && t.exec.call(this, values, parent)){
52567 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
52568 Roo.log(e.toString());
52573 var vs = t.target ? t.target.call(this, values, parent) : values;
52574 parent = t.target ? values : parent;
52575 if(t.target && vs instanceof Array){
52577 for(var i = 0, len = vs.length; i < len; i++){
52578 buf[buf.length] = t.compiled.call(this, vs[i], parent);
52580 return buf.join('');
52582 return t.compiled.call(this, vs, parent);
52584 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
52585 Roo.log(e.toString());
52586 Roo.log(t.compiled);
52591 compileTpl : function(tpl)
52593 var fm = Roo.util.Format;
52594 var useF = this.disableFormats !== true;
52595 var sep = Roo.isGecko ? "+" : ",";
52596 var undef = function(str) {
52597 Roo.log("Property not found :" + str);
52601 var fn = function(m, name, format, args)
52603 //Roo.log(arguments);
52604 args = args ? args.replace(/\\'/g,"'") : args;
52605 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
52606 if (typeof(format) == 'undefined') {
52607 format= 'htmlEncode';
52609 if (format == 'raw' ) {
52613 if(name.substr(0, 4) == 'xtpl'){
52614 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
52617 // build an array of options to determine if value is undefined..
52619 // basically get 'xxxx.yyyy' then do
52620 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
52621 // (function () { Roo.log("Property not found"); return ''; })() :
52626 Roo.each(name.split('.'), function(st) {
52627 lookfor += (lookfor.length ? '.': '') + st;
52628 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
52631 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
52634 if(format && useF){
52636 args = args ? ',' + args : "";
52638 if(format.substr(0, 5) != "this."){
52639 format = "fm." + format + '(';
52641 format = 'this.call("'+ format.substr(5) + '", ';
52645 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
52649 // called with xxyx.yuu:(test,test)
52651 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
52653 // raw.. - :raw modifier..
52654 return "'"+ sep + udef_st + name + ")"+sep+"'";
52658 // branched to use + in gecko and [].join() in others
52660 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
52661 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
52664 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
52665 body.push(tpl.body.replace(/(\r\n|\n)/g,
52666 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
52667 body.push("'].join('');};};");
52668 body = body.join('');
52671 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
52673 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
52679 applyTemplate : function(values){
52680 return this.master.compiled.call(this, values, {});
52681 //var s = this.subs;
52684 apply : function(){
52685 return this.applyTemplate.apply(this, arguments);
52690 Roo.XTemplate.from = function(el){
52691 el = Roo.getDom(el);
52692 return new Roo.XTemplate(el.value || el.innerHTML);
52694 * Original code for Roojs - LGPL
52695 * <script type="text/javascript">
52699 * @class Roo.XComponent
52700 * A delayed Element creator...
52701 * Or a way to group chunks of interface together.
52703 * Mypart.xyx = new Roo.XComponent({
52705 parent : 'Mypart.xyz', // empty == document.element.!!
52709 disabled : function() {}
52711 tree : function() { // return an tree of xtype declared components
52715 xtype : 'NestedLayoutPanel',
52722 * It can be used to build a big heiracy, with parent etc.
52723 * or you can just use this to render a single compoent to a dom element
52724 * MYPART.render(Roo.Element | String(id) | dom_element )
52726 * @extends Roo.util.Observable
52728 * @param cfg {Object} configuration of component
52731 Roo.XComponent = function(cfg) {
52732 Roo.apply(this, cfg);
52736 * Fires when this the componnt is built
52737 * @param {Roo.XComponent} c the component
52742 this.region = this.region || 'center'; // default..
52743 Roo.XComponent.register(this);
52744 this.modules = false;
52745 this.el = false; // where the layout goes..
52749 Roo.extend(Roo.XComponent, Roo.util.Observable, {
52752 * The created element (with Roo.factory())
52753 * @type {Roo.Layout}
52759 * for BC - use el in new code
52760 * @type {Roo.Layout}
52766 * for BC - use el in new code
52767 * @type {Roo.Layout}
52772 * @cfg {Function|boolean} disabled
52773 * If this module is disabled by some rule, return true from the funtion
52778 * @cfg {String} parent
52779 * Name of parent element which it get xtype added to..
52784 * @cfg {String} order
52785 * Used to set the order in which elements are created (usefull for multiple tabs)
52790 * @cfg {String} name
52791 * String to display while loading.
52795 * @cfg {String} region
52796 * Region to render component to (defaults to center)
52801 * @cfg {Array} items
52802 * A single item array - the first element is the root of the tree..
52803 * It's done this way to stay compatible with the Xtype system...
52809 * The method that retuns the tree of parts that make up this compoennt
52816 * render element to dom or tree
52817 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
52820 render : function(el)
52824 var hp = this.parent ? 1 : 0;
52826 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
52827 // if parent is a '#.....' string, then let's use that..
52828 var ename = this.parent.substr(1)
52829 this.parent = false;
52830 el = Roo.get(ename);
52832 Roo.log("Warning - element can not be found :#" + ename );
52838 if (!this.parent) {
52840 el = el ? Roo.get(el) : false;
52842 // it's a top level one..
52844 el : new Roo.BorderLayout(el || document.body, {
52850 tabPosition: 'top',
52851 //resizeTabs: true,
52852 alwaysShowTabs: el && hp? false : true,
52853 hideTabs: el || !hp ? true : false,
52861 // The 'tree' method is '_tree now'
52863 var tree = this._tree ? this._tree() : this.tree();
52864 tree.region = tree.region || this.region;
52865 this.el = this.parent.el.addxtype(tree);
52866 this.fireEvent('built', this);
52868 this.panel = this.el;
52869 this.layout = this.panel.layout;
52870 this.parentLayout = this.parent.layout || false;
52876 Roo.apply(Roo.XComponent, {
52879 * @property buildCompleted
52880 * True when the builder has completed building the interface.
52883 buildCompleted : false,
52886 * @property topModule
52887 * the upper most module - uses document.element as it's constructor.
52894 * @property modules
52895 * array of modules to be created by registration system.
52896 * @type {Array} of Roo.XComponent
52901 * @property elmodules
52902 * array of modules to be created by which use #ID
52903 * @type {Array} of Roo.XComponent
52910 * Register components to be built later.
52912 * This solves the following issues
52913 * - Building is not done on page load, but after an authentication process has occured.
52914 * - Interface elements are registered on page load
52915 * - Parent Interface elements may not be loaded before child, so this handles that..
52922 module : 'Pman.Tab.projectMgr',
52924 parent : 'Pman.layout',
52925 disabled : false, // or use a function..
52928 * * @param {Object} details about module
52930 register : function(obj) {
52932 Roo.XComponent.event.fireEvent('register', obj);
52933 switch(typeof(obj.disabled) ) {
52939 if ( obj.disabled() ) {
52944 if (obj.disabled) {
52950 this.modules.push(obj);
52954 * convert a string to an object..
52955 * eg. 'AAA.BBB' -> finds AAA.BBB
52959 toObject : function(str)
52961 if (!str || typeof(str) == 'object') {
52964 if (str.substring(0,1) == '#') {
52968 var ar = str.split('.');
52973 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
52975 throw "Module not found : " + str;
52979 throw "Module not found : " + str;
52981 Roo.each(ar, function(e) {
52982 if (typeof(o[e]) == 'undefined') {
52983 throw "Module not found : " + str;
52994 * move modules into their correct place in the tree..
52997 preBuild : function ()
53000 Roo.each(this.modules , function (obj)
53002 var opar = obj.parent;
53004 obj.parent = this.toObject(opar);
53006 Roo.log("parent:toObject failed: " + e.toString());
53011 Roo.debug && Roo.log("GOT top level module");
53012 Roo.debug && Roo.log(obj);
53013 obj.modules = new Roo.util.MixedCollection(false,
53014 function(o) { return o.order + '' }
53016 this.topModule = obj;
53019 // parent is a string (usually a dom element name..)
53020 if (typeof(obj.parent) == 'string') {
53021 this.elmodules.push(obj);
53024 if (obj.parent.constructor != Roo.XComponent) {
53025 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
53027 if (!obj.parent.modules) {
53028 obj.parent.modules = new Roo.util.MixedCollection(false,
53029 function(o) { return o.order + '' }
53033 obj.parent.modules.add(obj);
53038 * make a list of modules to build.
53039 * @return {Array} list of modules.
53042 buildOrder : function()
53045 var cmp = function(a,b) {
53046 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
53048 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
53049 throw "No top level modules to build";
53052 // make a flat list in order of modules to build.
53053 var mods = this.topModule ? [ this.topModule ] : [];
53055 // elmodules (is a list of DOM based modules )
53056 Roo.each(this.elmodules,function(e) { mods.push(e) });
53059 // add modules to their parents..
53060 var addMod = function(m) {
53061 Roo.debug && Roo.log("build Order: add: " + m.name);
53065 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
53066 m.modules.keySort('ASC', cmp );
53067 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
53069 m.modules.each(addMod);
53071 Roo.debug && Roo.log("build Order: no child modules");
53073 // not sure if this is used any more..
53075 m.finalize.name = m.name + " (clean up) ";
53076 mods.push(m.finalize);
53080 if (this.topModule) {
53081 this.topModule.modules.keySort('ASC', cmp );
53082 this.topModule.modules.each(addMod);
53088 * Build the registered modules.
53089 * @param {Object} parent element.
53090 * @param {Function} optional method to call after module has been added.
53098 var mods = this.buildOrder();
53100 //this.allmods = mods;
53101 //Roo.debug && Roo.log(mods);
53103 if (!mods.length) { // should not happen
53104 throw "NO modules!!!";
53108 var msg = "Building Interface...";
53109 // flash it up as modal - so we store the mask!?
53110 Roo.MessageBox.show({ title: 'loading' });
53111 Roo.MessageBox.show({
53112 title: "Please wait...",
53120 var total = mods.length;
53123 var progressRun = function() {
53124 if (!mods.length) {
53125 Roo.debug && Roo.log('hide?');
53126 Roo.MessageBox.hide();
53127 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
53133 var m = mods.shift();
53136 Roo.debug && Roo.log(m);
53137 // not sure if this is supported any more.. - modules that are are just function
53138 if (typeof(m) == 'function') {
53140 return progressRun.defer(10, _this);
53144 msg = "Building Interface " + (total - mods.length) +
53146 (m.name ? (' - ' + m.name) : '');
53147 Roo.debug && Roo.log(msg);
53148 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
53151 // is the module disabled?
53152 var disabled = (typeof(m.disabled) == 'function') ?
53153 m.disabled.call(m.module.disabled) : m.disabled;
53157 return progressRun(); // we do not update the display!
53165 // it's 10 on top level, and 1 on others??? why...
53166 return progressRun.defer(10, _this);
53169 progressRun.defer(1, _this);
53183 * wrapper for event.on - aliased later..
53184 * Typically use to register a event handler for register:
53186 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
53195 Roo.XComponent.event = new Roo.util.Observable({
53199 * Fires when an Component is registered,
53200 * set the disable property on the Component to stop registration.
53201 * @param {Roo.XComponent} c the component being registerd.
53206 * @event buildcomplete
53207 * Fires on the top level element when all elements have been built
53208 * @param {Roo.XComponent} the top level component.
53210 'buildcomplete' : true
53215 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
53216 //<script type="text/javascript">
53221 * @extends Roo.LayoutDialog
53222 * A generic Login Dialog..... - only one needed in theory!?!?
53224 * Fires XComponent builder on success...
53227 * username,password, lang = for login actions.
53228 * check = 1 for periodic checking that sesion is valid.
53229 * passwordRequest = email request password
53230 * logout = 1 = to logout
53232 * Affects: (this id="????" elements)
53233 * loading (removed) (used to indicate application is loading)
53234 * loading-mask (hides) (used to hide application when it's building loading)
53240 * Myapp.login = Roo.Login({
53256 Roo.Login = function(cfg)
53262 Roo.apply(this,cfg);
53264 Roo.onReady(function() {
53270 Roo.Login.superclass.constructor.call(this, this);
53271 //this.addxtype(this.items[0]);
53277 Roo.extend(Roo.Login, Roo.LayoutDialog, {
53280 * @cfg {String} method
53281 * Method used to query for login details.
53286 * @cfg {String} url
53287 * URL to query login data. - eg. baseURL + '/Login.php'
53293 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
53298 * @property checkFails
53299 * Number of times we have attempted to get authentication check, and failed.
53304 * @property intervalID
53305 * The window interval that does the constant login checking.
53311 onLoad : function() // called on page load...
53315 if (Roo.get('loading')) { // clear any loading indicator..
53316 Roo.get('loading').remove();
53319 //this.switchLang('en'); // set the language to english..
53322 success: function(response, opts) { // check successfull...
53324 var res = this.processResponse(response);
53325 this.checkFails =0;
53326 if (!res.success) { // error!
53327 this.checkFails = 5;
53328 //console.log('call failure');
53329 return this.failure(response,opts);
53332 if (!res.data.id) { // id=0 == login failure.
53333 return this.show();
53337 //console.log(success);
53338 this.fillAuth(res.data);
53339 this.checkFails =0;
53340 Roo.XComponent.build();
53342 failure : this.show
53348 check: function(cfg) // called every so often to refresh cookie etc..
53350 if (cfg.again) { // could be undefined..
53353 this.checkFails = 0;
53356 if (this.sending) {
53357 if ( this.checkFails > 4) {
53358 Roo.MessageBox.alert("Error",
53359 "Error getting authentication status. - try reloading, or wait a while", function() {
53360 _this.sending = false;
53365 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
53368 this.sending = true;
53375 method: this.method,
53376 success: cfg.success || this.success,
53377 failure : cfg.failure || this.failure,
53387 window.onbeforeunload = function() { }; // false does not work for IE..
53397 failure : function() {
53398 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
53399 document.location = document.location.toString() + '?ts=' + Math.random();
53403 success : function() {
53404 _this.user = false;
53405 this.checkFails =0;
53407 document.location = document.location.toString() + '?ts=' + Math.random();
53414 processResponse : function (response)
53418 res = Roo.decode(response.responseText);
53420 if (typeof(res) != 'object') {
53421 res = { success : false, errorMsg : res, errors : true };
53423 if (typeof(res.success) == 'undefined') {
53424 res.success = false;
53428 res = { success : false, errorMsg : response.responseText, errors : true };
53433 success : function(response, opts) // check successfull...
53435 this.sending = false;
53436 var res = this.processResponse(response);
53437 if (!res.success) {
53438 return this.failure(response, opts);
53440 if (!res.data || !res.data.id) {
53441 return this.failure(response,opts);
53443 //console.log(res);
53444 this.fillAuth(res.data);
53446 this.checkFails =0;
53451 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
53453 this.authUser = -1;
53454 this.sending = false;
53455 var res = this.processResponse(response);
53456 //console.log(res);
53457 if ( this.checkFails > 2) {
53459 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
53460 "Error getting authentication status. - try reloading");
53463 opts.callCfg.again = true;
53464 this.check.defer(1000, this, [ opts.callCfg ]);
53470 fillAuth: function(au) {
53471 this.startAuthCheck();
53472 this.authUserId = au.id;
53473 this.authUser = au;
53474 this.lastChecked = new Date();
53475 this.fireEvent('refreshed', au);
53476 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
53477 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
53478 au.lang = au.lang || 'en';
53479 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
53480 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
53481 this.switchLang(au.lang );
53484 // open system... - -on setyp..
53485 if (this.authUserId < 0) {
53486 Roo.MessageBox.alert("Warning",
53487 "This is an open system - please set up a admin user with a password.");
53490 //Pman.onload(); // which should do nothing if it's a re-auth result...
53495 startAuthCheck : function() // starter for timeout checking..
53497 if (this.intervalID) { // timer already in place...
53501 this.intervalID = window.setInterval(function() {
53502 _this.check(false);
53503 }, 120000); // every 120 secs = 2mins..
53509 switchLang : function (lang)
53511 _T = typeof(_T) == 'undefined' ? false : _T;
53512 if (!_T || !lang.length) {
53516 if (!_T && lang != 'en') {
53517 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53521 if (typeof(_T.en) == 'undefined') {
53523 Roo.apply(_T.en, _T);
53526 if (typeof(_T[lang]) == 'undefined') {
53527 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53532 Roo.apply(_T, _T[lang]);
53533 // just need to set the text values for everything...
53535 /* this will not work ...
53539 function formLabel(name, val) {
53540 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
53543 formLabel('password', "Password"+':');
53544 formLabel('username', "Email Address"+':');
53545 formLabel('lang', "Language"+':');
53546 this.dialog.setTitle("Login");
53547 this.dialog.buttons[0].setText("Forgot Password");
53548 this.dialog.buttons[1].setText("Login");
53567 collapsible: false,
53569 center: { // needed??
53572 // tabPosition: 'top',
53575 alwaysShowTabs: false
53579 show : function(dlg)
53581 //console.log(this);
53582 this.form = this.layout.getRegion('center').activePanel.form;
53583 this.form.dialog = dlg;
53584 this.buttons[0].form = this.form;
53585 this.buttons[0].dialog = dlg;
53586 this.buttons[1].form = this.form;
53587 this.buttons[1].dialog = dlg;
53589 //this.resizeToLogo.defer(1000,this);
53590 // this is all related to resizing for logos..
53591 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
53593 // this.resizeToLogo.defer(1000,this);
53596 //var w = Ext.lib.Dom.getViewWidth() - 100;
53597 //var h = Ext.lib.Dom.getViewHeight() - 100;
53598 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
53600 if (this.disabled) {
53605 if (this.user.id < 0) { // used for inital setup situations.
53609 if (this.intervalID) {
53610 // remove the timer
53611 window.clearInterval(this.intervalID);
53612 this.intervalID = false;
53616 if (Roo.get('loading')) {
53617 Roo.get('loading').remove();
53619 if (Roo.get('loading-mask')) {
53620 Roo.get('loading-mask').hide();
53623 //incomming._node = tnode;
53625 //this.dialog.modal = !modal;
53626 //this.dialog.show();
53630 this.form.setValues({
53631 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
53632 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
53635 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
53636 if (this.form.findField('username').getValue().length > 0 ){
53637 this.form.findField('password').focus();
53639 this.form.findField('username').focus();
53647 xtype : 'ContentPanel',
53659 style : 'margin: 10px;',
53662 actionfailed : function(f, act) {
53663 // form can return { errors: .... }
53665 //act.result.errors // invalid form element list...
53666 //act.result.errorMsg// invalid form element list...
53668 this.dialog.el.unmask();
53669 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
53670 "Login failed - communication error - try again.");
53673 actioncomplete: function(re, act) {
53675 Roo.state.Manager.set(
53676 this.dialog.realm + '.username',
53677 this.findField('username').getValue()
53679 Roo.state.Manager.set(
53680 this.dialog.realm + '.lang',
53681 this.findField('lang').getValue()
53684 this.dialog.fillAuth(act.result.data);
53686 this.dialog.hide();
53688 if (Roo.get('loading-mask')) {
53689 Roo.get('loading-mask').show();
53691 Roo.XComponent.build();
53699 xtype : 'TextField',
53701 fieldLabel: "Email Address",
53704 autoCreate : {tag: "input", type: "text", size: "20"}
53707 xtype : 'TextField',
53709 fieldLabel: "Password",
53710 inputType: 'password',
53713 autoCreate : {tag: "input", type: "text", size: "20"},
53715 specialkey : function(e,ev) {
53716 if (ev.keyCode == 13) {
53717 this.form.dialog.el.mask("Logging in");
53718 this.form.doAction('submit', {
53719 url: this.form.dialog.url,
53720 method: this.form.dialog.method
53727 xtype : 'ComboBox',
53729 fieldLabel: "Language",
53732 xtype : 'SimpleStore',
53733 fields: ['lang', 'ldisp'],
53735 [ 'en', 'English' ],
53736 [ 'zh_HK' , '\u7E41\u4E2D' ],
53737 [ 'zh_CN', '\u7C21\u4E2D' ]
53741 valueField : 'lang',
53742 hiddenName: 'lang',
53744 displayField:'ldisp',
53748 triggerAction: 'all',
53749 emptyText:'Select a Language...',
53750 selectOnFocus:true,
53752 select : function(cb, rec, ix) {
53753 this.form.switchLang(rec.data.lang);
53769 text : "Forgot Password",
53771 click : function() {
53772 //console.log(this);
53773 var n = this.form.findField('username').getValue();
53775 Roo.MessageBox.alert("Error", "Fill in your email address");
53779 url: this.dialog.url,
53783 method: this.dialog.method,
53784 success: function(response, opts) { // check successfull...
53786 var res = this.dialog.processResponse(response);
53787 if (!res.success) { // error!
53788 Roo.MessageBox.alert("Error" ,
53789 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
53792 Roo.MessageBox.alert("Notice" ,
53793 "Please check you email for the Password Reset message");
53795 failure : function() {
53796 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
53809 click : function () {
53811 this.dialog.el.mask("Logging in");
53812 this.form.doAction('submit', {
53813 url: this.dialog.url,
53814 method: this.dialog.method