4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1010 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1011 T CST Timezone setting of the machine running the code
1012 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1015 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d')); //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1020 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1023 * Here are some standard date/time patterns that you might find helpful. They
1024 * are not part of the source of Date.js, but to use them you can simply copy this
1025 * block of code into any script that is included after Date.js and they will also become
1026 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1029 ISO8601Long:"Y-m-d H:i:s",
1030 ISO8601Short:"Y-m-d",
1032 LongDate: "l, F d, Y",
1033 FullDateTime: "l, F d, Y g:i:s A",
1036 LongTime: "g:i:s A",
1037 SortableDateTime: "Y-m-d\\TH:i:s",
1038 UniversalSortableDateTime: "Y-m-d H:i:sO",
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1051 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052 * They generate precompiled functions from date formats instead of parsing and
1053 * processing the pattern every time you format a date. These functions are available
1054 * on every Date object (any javascript function).
1056 * The original article and download are here:
1057 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1064 Returns the number of milliseconds between this date and date
1065 @param {Date} date (optional) Defaults to now
1066 @return {Number} The diff in milliseconds
1067 @member Date getElapsed
1069 Date.prototype.getElapsed = function(date) {
1070 return Math.abs((date || new Date()).getTime()-this.getTime());
1072 // was in date file..
1076 Date.parseFunctions = {count:0};
1078 Date.parseRegexes = [];
1080 Date.formatFunctions = {count:0};
1083 Date.prototype.dateFormat = function(format) {
1084 if (Date.formatFunctions[format] == null) {
1085 Date.createNewFormat(format);
1087 var func = Date.formatFunctions[format];
1088 return this[func]();
1093 * Formats a date given the supplied format string
1094 * @param {String} format The format string
1095 * @return {String} The formatted date
1098 Date.prototype.format = Date.prototype.dateFormat;
1101 Date.createNewFormat = function(format) {
1102 var funcName = "format" + Date.formatFunctions.count++;
1103 Date.formatFunctions[format] = funcName;
1104 var code = "Date.prototype." + funcName + " = function(){return ";
1105 var special = false;
1107 for (var i = 0; i < format.length; ++i) {
1108 ch = format.charAt(i);
1109 if (!special && ch == "\\") {
1114 code += "'" + String.escape(ch) + "' + ";
1117 code += Date.getFormatCode(ch);
1120 /** eval:var:zzzzzzzzzzzzz */
1121 eval(code.substring(0, code.length - 3) + ";}");
1125 Date.getFormatCode = function(character) {
1126 switch (character) {
1128 return "String.leftPad(this.getDate(), 2, '0') + ";
1130 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1132 return "this.getDate() + ";
1134 return "Date.dayNames[this.getDay()] + ";
1136 return "this.getSuffix() + ";
1138 return "this.getDay() + ";
1140 return "this.getDayOfYear() + ";
1142 return "this.getWeekOfYear() + ";
1144 return "Date.monthNames[this.getMonth()] + ";
1146 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1148 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1150 return "(this.getMonth() + 1) + ";
1152 return "this.getDaysInMonth() + ";
1154 return "(this.isLeapYear() ? 1 : 0) + ";
1156 return "this.getFullYear() + ";
1158 return "('' + this.getFullYear()).substring(2, 4) + ";
1160 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1162 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1164 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1166 return "this.getHours() + ";
1168 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1170 return "String.leftPad(this.getHours(), 2, '0') + ";
1172 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1174 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1176 return "this.getGMTOffset() + ";
1178 return "this.getGMTColonOffset() + ";
1180 return "this.getTimezone() + ";
1182 return "(this.getTimezoneOffset() * -60) + ";
1184 return "'" + String.escape(character) + "' + ";
1189 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1191 * the date format that is not specified will default to the current date value for that part. Time parts can also
1192 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1193 * string or the parse operation will fail.
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1208 * @param {String} input The unparsed date as a string
1209 * @param {String} format The format the date is in
1210 * @return {Date} The parsed date
1213 Date.parseDate = function(input, format) {
1214 if (Date.parseFunctions[format] == null) {
1215 Date.createParser(format);
1217 var func = Date.parseFunctions[format];
1218 return Date[func](input);
1223 Date.createParser = function(format) {
1224 var funcName = "parse" + Date.parseFunctions.count++;
1225 var regexNum = Date.parseRegexes.length;
1226 var currentGroup = 1;
1227 Date.parseFunctions[format] = funcName;
1229 var code = "Date." + funcName + " = function(input){\n"
1230 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231 + "var d = new Date();\n"
1232 + "y = d.getFullYear();\n"
1233 + "m = d.getMonth();\n"
1234 + "d = d.getDate();\n"
1235 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236 + "if (results && results.length > 0) {";
1239 var special = false;
1241 for (var i = 0; i < format.length; ++i) {
1242 ch = format.charAt(i);
1243 if (!special && ch == "\\") {
1248 regex += String.escape(ch);
1251 var obj = Date.formatCodeToRegex(ch, currentGroup);
1252 currentGroup += obj.g;
1254 if (obj.g && obj.c) {
1260 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261 + "{v = new Date(y, m, d, h, i, s);}\n"
1262 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265 + "{v = new Date(y, m, d, h);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267 + "{v = new Date(y, m, d);}\n"
1268 + "else if (y >= 0 && m >= 0)\n"
1269 + "{v = new Date(y, m);}\n"
1270 + "else if (y >= 0)\n"
1271 + "{v = new Date(y);}\n"
1272 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278 /** eval:var:zzzzzzzzzzzzz */
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284 switch (character) {
1288 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292 s:"(\\d{1,2})"}; // day of month without leading zeroes
1295 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296 s:"(\\d{2})"}; // day of month with leading zeroes
1300 s:"(?:" + Date.dayNames.join("|") + ")"};
1304 s:"(?:st|nd|rd|th)"};
1319 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320 s:"(" + Date.monthNames.join("|") + ")"};
1323 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1343 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1347 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1352 c:"if (results[" + currentGroup + "] == 'am') {\n"
1353 + "if (h == 12) { h = 0; }\n"
1354 + "} else { if (h < 12) { h += 12; }}",
1358 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1365 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1374 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1378 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1383 "o = results[", currentGroup, "];\n",
1384 "var sn = o.substring(0,1);\n", // get + / - sign
1385 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1390 s:"([+\-]\\d{2,4})"};
1396 "o = results[", currentGroup, "];\n",
1397 "var sn = o.substring(0,1);\n",
1398 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1399 "var mn = o.substring(4,6) % 60;\n",
1400 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1401 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1411 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1412 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1416 s:String.escape(character)};
1421 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1422 * @return {String} The abbreviated timezone name (e.g. 'CST')
1424 Date.prototype.getTimezone = function() {
1425 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1429 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1430 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1432 Date.prototype.getGMTOffset = function() {
1433 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1434 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1435 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1439 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1440 * @return {String} 2-characters representing hours and 2-characters representing minutes
1441 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1443 Date.prototype.getGMTColonOffset = function() {
1444 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1445 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1447 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1451 * Get the numeric day number of the year, adjusted for leap year.
1452 * @return {Number} 0 through 364 (365 in leap years)
1454 Date.prototype.getDayOfYear = function() {
1456 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1457 for (var i = 0; i < this.getMonth(); ++i) {
1458 num += Date.daysInMonth[i];
1460 return num + this.getDate() - 1;
1464 * Get the string representation of the numeric week number of the year
1465 * (equivalent to the format specifier 'W').
1466 * @return {String} '00' through '52'
1468 Date.prototype.getWeekOfYear = function() {
1469 // Skip to Thursday of this week
1470 var now = this.getDayOfYear() + (4 - this.getDay());
1471 // Find the first Thursday of the year
1472 var jan1 = new Date(this.getFullYear(), 0, 1);
1473 var then = (7 - jan1.getDay() + 4);
1474 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1478 * Whether or not the current date is in a leap year.
1479 * @return {Boolean} True if the current date is in a leap year, else false
1481 Date.prototype.isLeapYear = function() {
1482 var year = this.getFullYear();
1483 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1487 * Get the first day of the current month, adjusted for leap year. The returned value
1488 * is the numeric day index within the week (0-6) which can be used in conjunction with
1489 * the {@link #monthNames} array to retrieve the textual day name.
1492 var dt = new Date('1/10/2007');
1493 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1495 * @return {Number} The day number (0-6)
1497 Date.prototype.getFirstDayOfMonth = function() {
1498 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1499 return (day < 0) ? (day + 7) : day;
1503 * Get the last day of the current month, adjusted for leap year. The returned value
1504 * is the numeric day index within the week (0-6) which can be used in conjunction with
1505 * the {@link #monthNames} array to retrieve the textual day name.
1508 var dt = new Date('1/10/2007');
1509 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1511 * @return {Number} The day number (0-6)
1513 Date.prototype.getLastDayOfMonth = function() {
1514 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1515 return (day < 0) ? (day + 7) : day;
1520 * Get the first date of this date's month
1523 Date.prototype.getFirstDateOfMonth = function() {
1524 return new Date(this.getFullYear(), this.getMonth(), 1);
1528 * Get the last date of this date's month
1531 Date.prototype.getLastDateOfMonth = function() {
1532 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 * Get the number of days in the current month, adjusted for leap year.
1536 * @return {Number} The number of days in the month
1538 Date.prototype.getDaysInMonth = function() {
1539 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1540 return Date.daysInMonth[this.getMonth()];
1544 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1545 * @return {String} 'st, 'nd', 'rd' or 'th'
1547 Date.prototype.getSuffix = function() {
1548 switch (this.getDate()) {
1565 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568 * An array of textual month names.
1569 * Override these values for international dates, for example...
1570 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1589 * An array of textual day names.
1590 * Override these values for international dates, for example...
1591 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1607 Date.monthNumbers = {
1622 * Creates and returns a new Date instance with the exact same date value as the called instance.
1623 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1624 * variable will also be changed. When the intention is to create a new variable that will not
1625 * modify the original instance, you should create a clone.
1627 * Example of correctly cloning a date:
1630 var orig = new Date('10/1/2006');
1633 document.write(orig); //returns 'Thu Oct 05 2006'!
1636 var orig = new Date('10/1/2006');
1637 var copy = orig.clone();
1639 document.write(orig); //returns 'Thu Oct 01 2006'
1641 * @return {Date} The new Date instance
1643 Date.prototype.clone = function() {
1644 return new Date(this.getTime());
1648 * Clears any time information from this date
1649 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1650 @return {Date} this or the clone
1652 Date.prototype.clearTime = function(clone){
1654 return this.clone().clearTime();
1659 this.setMilliseconds(0);
1664 // safari setMonth is broken
1666 Date.brokenSetMonth = Date.prototype.setMonth;
1667 Date.prototype.setMonth = function(num){
1669 var n = Math.ceil(-num);
1670 var back_year = Math.ceil(n/12);
1671 var month = (n % 12) ? 12 - n % 12 : 0 ;
1672 this.setFullYear(this.getFullYear() - back_year);
1673 return Date.brokenSetMonth.call(this, month);
1675 return Date.brokenSetMonth.apply(this, arguments);
1680 /** Date interval constant
1684 /** Date interval constant
1688 /** Date interval constant
1692 /** Date interval constant
1696 /** Date interval constant
1700 /** Date interval constant
1704 /** Date interval constant
1710 * Provides a convenient method of performing basic date arithmetic. This method
1711 * does not modify the Date instance being called - it creates and returns
1712 * a new Date instance containing the resulting date value.
1717 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1718 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1720 //Negative values will subtract correctly:
1721 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1722 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1724 //You can even chain several calls together in one line!
1725 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1726 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729 * @param {String} interval A valid date interval enum value
1730 * @param {Number} value The amount to add to the current date
1731 * @return {Date} The new Date instance
1733 Date.prototype.add = function(interval, value){
1734 var d = this.clone();
1735 if (!interval || value === 0) return d;
1736 switch(interval.toLowerCase()){
1738 d.setMilliseconds(this.getMilliseconds() + value);
1741 d.setSeconds(this.getSeconds() + value);
1744 d.setMinutes(this.getMinutes() + value);
1747 d.setHours(this.getHours() + value);
1750 d.setDate(this.getDate() + value);
1753 var day = this.getDate();
1755 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758 d.setMonth(this.getMonth() + value);
1761 d.setFullYear(this.getFullYear() + value);
1768 * Ext JS Library 1.1.1
1769 * Copyright(c) 2006-2007, Ext JS, LLC.
1771 * Originally Released Under LGPL - original licence link has changed is not relivant.
1774 * <script type="text/javascript">
1778 * @class Roo.lib.Dom
1781 * Dom utils (from YIU afaik)
1786 * Get the view width
1787 * @param {Boolean} full True will get the full document, otherwise it's the view width
1788 * @return {Number} The width
1791 getViewWidth : function(full) {
1792 return full ? this.getDocumentWidth() : this.getViewportWidth();
1795 * Get the view height
1796 * @param {Boolean} full True will get the full document, otherwise it's the view height
1797 * @return {Number} The height
1799 getViewHeight : function(full) {
1800 return full ? this.getDocumentHeight() : this.getViewportHeight();
1803 getDocumentHeight: function() {
1804 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1805 return Math.max(scrollHeight, this.getViewportHeight());
1808 getDocumentWidth: function() {
1809 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1810 return Math.max(scrollWidth, this.getViewportWidth());
1813 getViewportHeight: function() {
1814 var height = self.innerHeight;
1815 var mode = document.compatMode;
1817 if ((mode || Roo.isIE) && !Roo.isOpera) {
1818 height = (mode == "CSS1Compat") ?
1819 document.documentElement.clientHeight :
1820 document.body.clientHeight;
1826 getViewportWidth: function() {
1827 var width = self.innerWidth;
1828 var mode = document.compatMode;
1830 if (mode || Roo.isIE) {
1831 width = (mode == "CSS1Compat") ?
1832 document.documentElement.clientWidth :
1833 document.body.clientWidth;
1838 isAncestor : function(p, c) {
1845 if (p.contains && !Roo.isSafari) {
1846 return p.contains(c);
1847 } else if (p.compareDocumentPosition) {
1848 return !!(p.compareDocumentPosition(c) & 16);
1850 var parent = c.parentNode;
1855 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858 parent = parent.parentNode;
1864 getRegion : function(el) {
1865 return Roo.lib.Region.getRegion(el);
1868 getY : function(el) {
1869 return this.getXY(el)[1];
1872 getX : function(el) {
1873 return this.getXY(el)[0];
1876 getXY : function(el) {
1877 var p, pe, b, scroll, bd = document.body;
1878 el = Roo.getDom(el);
1879 var fly = Roo.lib.AnimBase.fly;
1880 if (el.getBoundingClientRect) {
1881 b = el.getBoundingClientRect();
1882 scroll = fly(document).getScroll();
1883 return [b.left + scroll.left, b.top + scroll.top];
1889 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1896 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1903 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1904 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1911 if (p != el && pe.getStyle('overflow') != 'visible') {
1919 if (Roo.isSafari && hasAbsolute) {
1924 if (Roo.isGecko && !hasAbsolute) {
1926 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1927 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1931 while (p && p != bd) {
1932 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1944 setXY : function(el, xy) {
1945 el = Roo.fly(el, '_setXY');
1947 var pts = el.translatePoints(xy);
1948 if (xy[0] !== false) {
1949 el.dom.style.left = pts.left + "px";
1951 if (xy[1] !== false) {
1952 el.dom.style.top = pts.top + "px";
1956 setX : function(el, x) {
1957 this.setXY(el, [x, false]);
1960 setY : function(el, y) {
1961 this.setXY(el, [false, y]);
1965 * Portions of this file are based on pieces of Yahoo User Interface Library
1966 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1967 * YUI licensed under the BSD License:
1968 * http://developer.yahoo.net/yui/license.txt
1969 * <script type="text/javascript">
1973 Roo.lib.Event = function() {
1974 var loadComplete = false;
1976 var unloadListeners = [];
1978 var onAvailStack = [];
1980 var lastError = null;
1993 startInterval: function() {
1994 if (!this._interval) {
1996 var callback = function() {
1997 self._tryPreloadAttach();
1999 this._interval = setInterval(callback, this.POLL_INTERVAL);
2004 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2005 onAvailStack.push({ id: p_id,
2008 override: p_override,
2009 checkReady: false });
2011 retryCount = this.POLL_RETRYS;
2012 this.startInterval();
2016 addListener: function(el, eventName, fn) {
2017 el = Roo.getDom(el);
2022 if ("unload" == eventName) {
2023 unloadListeners[unloadListeners.length] =
2024 [el, eventName, fn];
2028 var wrappedFn = function(e) {
2029 return fn(Roo.lib.Event.getEvent(e));
2032 var li = [el, eventName, fn, wrappedFn];
2034 var index = listeners.length;
2035 listeners[index] = li;
2037 this.doAdd(el, eventName, wrappedFn, false);
2043 removeListener: function(el, eventName, fn) {
2046 el = Roo.getDom(el);
2049 return this.purgeElement(el, false, eventName);
2053 if ("unload" == eventName) {
2055 for (i = 0,len = unloadListeners.length; i < len; i++) {
2056 var li = unloadListeners[i];
2059 li[1] == eventName &&
2061 unloadListeners.splice(i, 1);
2069 var cacheItem = null;
2072 var index = arguments[3];
2074 if ("undefined" == typeof index) {
2075 index = this._getCacheIndex(el, eventName, fn);
2079 cacheItem = listeners[index];
2082 if (!el || !cacheItem) {
2086 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2088 delete listeners[index][this.WFN];
2089 delete listeners[index][this.FN];
2090 listeners.splice(index, 1);
2097 getTarget: function(ev, resolveTextNode) {
2098 ev = ev.browserEvent || ev;
2099 var t = ev.target || ev.srcElement;
2100 return this.resolveTextNode(t);
2104 resolveTextNode: function(node) {
2105 if (Roo.isSafari && node && 3 == node.nodeType) {
2106 return node.parentNode;
2113 getPageX: function(ev) {
2114 ev = ev.browserEvent || ev;
2116 if (!x && 0 !== x) {
2117 x = ev.clientX || 0;
2120 x += this.getScroll()[1];
2128 getPageY: function(ev) {
2129 ev = ev.browserEvent || ev;
2131 if (!y && 0 !== y) {
2132 y = ev.clientY || 0;
2135 y += this.getScroll()[0];
2144 getXY: function(ev) {
2145 ev = ev.browserEvent || ev;
2146 return [this.getPageX(ev), this.getPageY(ev)];
2150 getRelatedTarget: function(ev) {
2151 ev = ev.browserEvent || ev;
2152 var t = ev.relatedTarget;
2154 if (ev.type == "mouseout") {
2156 } else if (ev.type == "mouseover") {
2161 return this.resolveTextNode(t);
2165 getTime: function(ev) {
2166 ev = ev.browserEvent || ev;
2168 var t = new Date().getTime();
2172 this.lastError = ex;
2181 stopEvent: function(ev) {
2182 this.stopPropagation(ev);
2183 this.preventDefault(ev);
2187 stopPropagation: function(ev) {
2188 ev = ev.browserEvent || ev;
2189 if (ev.stopPropagation) {
2190 ev.stopPropagation();
2192 ev.cancelBubble = true;
2197 preventDefault: function(ev) {
2198 ev = ev.browserEvent || ev;
2199 if(ev.preventDefault) {
2200 ev.preventDefault();
2202 ev.returnValue = false;
2207 getEvent: function(e) {
2208 var ev = e || window.event;
2210 var c = this.getEvent.caller;
2212 ev = c.arguments[0];
2213 if (ev && Event == ev.constructor) {
2223 getCharCode: function(ev) {
2224 ev = ev.browserEvent || ev;
2225 return ev.charCode || ev.keyCode || 0;
2229 _getCacheIndex: function(el, eventName, fn) {
2230 for (var i = 0,len = listeners.length; i < len; ++i) {
2231 var li = listeners[i];
2233 li[this.FN] == fn &&
2234 li[this.EL] == el &&
2235 li[this.TYPE] == eventName) {
2247 getEl: function(id) {
2248 return document.getElementById(id);
2252 clearCache: function() {
2256 _load: function(e) {
2257 loadComplete = true;
2258 var EU = Roo.lib.Event;
2262 EU.doRemove(window, "load", EU._load);
2267 _tryPreloadAttach: function() {
2276 var tryAgain = !loadComplete;
2278 tryAgain = (retryCount > 0);
2283 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2284 var item = onAvailStack[i];
2286 var el = this.getEl(item.id);
2289 if (!item.checkReady ||
2292 (document && document.body)) {
2295 if (item.override) {
2296 if (item.override === true) {
2299 scope = item.override;
2302 item.fn.call(scope, item.obj);
2303 onAvailStack[i] = null;
2306 notAvail.push(item);
2311 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2315 this.startInterval();
2317 clearInterval(this._interval);
2318 this._interval = null;
2321 this.locked = false;
2328 purgeElement: function(el, recurse, eventName) {
2329 var elListeners = this.getListeners(el, eventName);
2331 for (var i = 0,len = elListeners.length; i < len; ++i) {
2332 var l = elListeners[i];
2333 this.removeListener(el, l.type, l.fn);
2337 if (recurse && el && el.childNodes) {
2338 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2339 this.purgeElement(el.childNodes[i], recurse, eventName);
2345 getListeners: function(el, eventName) {
2346 var results = [], searchLists;
2348 searchLists = [listeners, unloadListeners];
2349 } else if (eventName == "unload") {
2350 searchLists = [unloadListeners];
2352 searchLists = [listeners];
2355 for (var j = 0; j < searchLists.length; ++j) {
2356 var searchList = searchLists[j];
2357 if (searchList && searchList.length > 0) {
2358 for (var i = 0,len = searchList.length; i < len; ++i) {
2359 var l = searchList[i];
2360 if (l && l[this.EL] === el &&
2361 (!eventName || eventName === l[this.TYPE])) {
2366 adjust: l[this.ADJ_SCOPE],
2374 return (results.length) ? results : null;
2378 _unload: function(e) {
2380 var EU = Roo.lib.Event, i, j, l, len, index;
2382 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2383 l = unloadListeners[i];
2386 if (l[EU.ADJ_SCOPE]) {
2387 if (l[EU.ADJ_SCOPE] === true) {
2390 scope = l[EU.ADJ_SCOPE];
2393 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2394 unloadListeners[i] = null;
2400 unloadListeners = null;
2402 if (listeners && listeners.length > 0) {
2403 j = listeners.length;
2406 l = listeners[index];
2408 EU.removeListener(l[EU.EL], l[EU.TYPE],
2418 EU.doRemove(window, "unload", EU._unload);
2423 getScroll: function() {
2424 var dd = document.documentElement, db = document.body;
2425 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2426 return [dd.scrollTop, dd.scrollLeft];
2428 return [db.scrollTop, db.scrollLeft];
2435 doAdd: function () {
2436 if (window.addEventListener) {
2437 return function(el, eventName, fn, capture) {
2438 el.addEventListener(eventName, fn, (capture));
2440 } else if (window.attachEvent) {
2441 return function(el, eventName, fn, capture) {
2442 el.attachEvent("on" + eventName, fn);
2451 doRemove: function() {
2452 if (window.removeEventListener) {
2453 return function (el, eventName, fn, capture) {
2454 el.removeEventListener(eventName, fn, (capture));
2456 } else if (window.detachEvent) {
2457 return function (el, eventName, fn) {
2458 el.detachEvent("on" + eventName, fn);
2470 var E = Roo.lib.Event;
2471 E.on = E.addListener;
2472 E.un = E.removeListener;
2474 if (document && document.body) {
2477 E.doAdd(window, "load", E._load);
2479 E.doAdd(window, "unload", E._unload);
2480 E._tryPreloadAttach();
2484 * Portions of this file are based on pieces of Yahoo User Interface Library
2485 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2486 * YUI licensed under the BSD License:
2487 * http://developer.yahoo.net/yui/license.txt
2488 * <script type="text/javascript">
2494 * @class Roo.lib.Ajax
2501 request : function(method, uri, cb, data, options) {
2503 var hs = options.headers;
2506 if(hs.hasOwnProperty(h)){
2507 this.initHeader(h, hs[h], false);
2511 if(options.xmlData){
2512 this.initHeader('Content-Type', 'text/xml', false);
2514 data = options.xmlData;
2518 return this.asyncRequest(method, uri, cb, data);
2521 serializeForm : function(form) {
2522 if(typeof form == 'string') {
2523 form = (document.getElementById(form) || document.forms[form]);
2526 var el, name, val, disabled, data = '', hasSubmit = false;
2527 for (var i = 0; i < form.elements.length; i++) {
2528 el = form.elements[i];
2529 disabled = form.elements[i].disabled;
2530 name = form.elements[i].name;
2531 val = form.elements[i].value;
2533 if (!disabled && name){
2537 case 'select-multiple':
2538 for (var j = 0; j < el.options.length; j++) {
2539 if (el.options[j].selected) {
2541 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2544 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2565 if(hasSubmit == false) {
2566 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2571 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2576 data = data.substr(0, data.length - 1);
2584 useDefaultHeader:true,
2586 defaultPostHeader:'application/x-www-form-urlencoded',
2588 useDefaultXhrHeader:true,
2590 defaultXhrHeader:'XMLHttpRequest',
2592 hasDefaultHeaders:true,
2604 setProgId:function(id)
2606 this.activeX.unshift(id);
2609 setDefaultPostHeader:function(b)
2611 this.useDefaultHeader = b;
2614 setDefaultXhrHeader:function(b)
2616 this.useDefaultXhrHeader = b;
2619 setPollingInterval:function(i)
2621 if (typeof i == 'number' && isFinite(i)) {
2622 this.pollInterval = i;
2626 createXhrObject:function(transactionId)
2632 http = new XMLHttpRequest();
2634 obj = { conn:http, tId:transactionId };
2638 for (var i = 0; i < this.activeX.length; ++i) {
2642 http = new ActiveXObject(this.activeX[i]);
2644 obj = { conn:http, tId:transactionId };
2657 getConnectionObject:function()
2660 var tId = this.transactionId;
2664 o = this.createXhrObject(tId);
2666 this.transactionId++;
2677 asyncRequest:function(method, uri, callback, postData)
2679 var o = this.getConnectionObject();
2685 o.conn.open(method, uri, true);
2687 if (this.useDefaultXhrHeader) {
2688 if (!this.defaultHeaders['X-Requested-With']) {
2689 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2693 if(postData && this.useDefaultHeader){
2694 this.initHeader('Content-Type', this.defaultPostHeader);
2697 if (this.hasDefaultHeaders || this.hasHeaders) {
2701 this.handleReadyState(o, callback);
2702 o.conn.send(postData || null);
2708 handleReadyState:function(o, callback)
2712 if (callback && callback.timeout) {
2713 this.timeout[o.tId] = window.setTimeout(function() {
2714 oConn.abort(o, callback, true);
2715 }, callback.timeout);
2718 this.poll[o.tId] = window.setInterval(
2720 if (o.conn && o.conn.readyState == 4) {
2721 window.clearInterval(oConn.poll[o.tId]);
2722 delete oConn.poll[o.tId];
2724 if(callback && callback.timeout) {
2725 window.clearTimeout(oConn.timeout[o.tId]);
2726 delete oConn.timeout[o.tId];
2729 oConn.handleTransactionResponse(o, callback);
2732 , this.pollInterval);
2735 handleTransactionResponse:function(o, callback, isAbort)
2739 this.releaseObject(o);
2743 var httpStatus, responseObject;
2747 if (o.conn.status !== undefined && o.conn.status != 0) {
2748 httpStatus = o.conn.status;
2760 if (httpStatus >= 200 && httpStatus < 300) {
2761 responseObject = this.createResponseObject(o, callback.argument);
2762 if (callback.success) {
2763 if (!callback.scope) {
2764 callback.success(responseObject);
2769 callback.success.apply(callback.scope, [responseObject]);
2774 switch (httpStatus) {
2782 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2783 if (callback.failure) {
2784 if (!callback.scope) {
2785 callback.failure(responseObject);
2788 callback.failure.apply(callback.scope, [responseObject]);
2793 responseObject = this.createResponseObject(o, callback.argument);
2794 if (callback.failure) {
2795 if (!callback.scope) {
2796 callback.failure(responseObject);
2799 callback.failure.apply(callback.scope, [responseObject]);
2805 this.releaseObject(o);
2806 responseObject = null;
2809 createResponseObject:function(o, callbackArg)
2816 var headerStr = o.conn.getAllResponseHeaders();
2817 var header = headerStr.split('\n');
2818 for (var i = 0; i < header.length; i++) {
2819 var delimitPos = header[i].indexOf(':');
2820 if (delimitPos != -1) {
2821 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2829 obj.status = o.conn.status;
2830 obj.statusText = o.conn.statusText;
2831 obj.getResponseHeader = headerObj;
2832 obj.getAllResponseHeaders = headerStr;
2833 obj.responseText = o.conn.responseText;
2834 obj.responseXML = o.conn.responseXML;
2836 if (typeof callbackArg !== undefined) {
2837 obj.argument = callbackArg;
2843 createExceptionObject:function(tId, callbackArg, isAbort)
2846 var COMM_ERROR = 'communication failure';
2847 var ABORT_CODE = -1;
2848 var ABORT_ERROR = 'transaction aborted';
2854 obj.status = ABORT_CODE;
2855 obj.statusText = ABORT_ERROR;
2858 obj.status = COMM_CODE;
2859 obj.statusText = COMM_ERROR;
2863 obj.argument = callbackArg;
2869 initHeader:function(label, value, isDefault)
2871 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2873 if (headerObj[label] === undefined) {
2874 headerObj[label] = value;
2879 headerObj[label] = value + "," + headerObj[label];
2883 this.hasDefaultHeaders = true;
2886 this.hasHeaders = true;
2891 setHeader:function(o)
2893 if (this.hasDefaultHeaders) {
2894 for (var prop in this.defaultHeaders) {
2895 if (this.defaultHeaders.hasOwnProperty(prop)) {
2896 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2901 if (this.hasHeaders) {
2902 for (var prop in this.headers) {
2903 if (this.headers.hasOwnProperty(prop)) {
2904 o.conn.setRequestHeader(prop, this.headers[prop]);
2908 this.hasHeaders = false;
2912 resetDefaultHeaders:function() {
2913 delete this.defaultHeaders;
2914 this.defaultHeaders = {};
2915 this.hasDefaultHeaders = false;
2918 abort:function(o, callback, isTimeout)
2920 if(this.isCallInProgress(o)) {
2922 window.clearInterval(this.poll[o.tId]);
2923 delete this.poll[o.tId];
2925 delete this.timeout[o.tId];
2928 this.handleTransactionResponse(o, callback, true);
2938 isCallInProgress:function(o)
2941 return o.conn.readyState != 4 && o.conn.readyState != 0;
2950 releaseObject:function(o)
2959 'MSXML2.XMLHTTP.3.0',
2967 * Portions of this file are based on pieces of Yahoo User Interface Library
2968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2969 * YUI licensed under the BSD License:
2970 * http://developer.yahoo.net/yui/license.txt
2971 * <script type="text/javascript">
2975 Roo.lib.Region = function(t, r, b, l) {
2985 Roo.lib.Region.prototype = {
2986 contains : function(region) {
2987 return ( region.left >= this.left &&
2988 region.right <= this.right &&
2989 region.top >= this.top &&
2990 region.bottom <= this.bottom );
2994 getArea : function() {
2995 return ( (this.bottom - this.top) * (this.right - this.left) );
2998 intersect : function(region) {
2999 var t = Math.max(this.top, region.top);
3000 var r = Math.min(this.right, region.right);
3001 var b = Math.min(this.bottom, region.bottom);
3002 var l = Math.max(this.left, region.left);
3004 if (b >= t && r >= l) {
3005 return new Roo.lib.Region(t, r, b, l);
3010 union : function(region) {
3011 var t = Math.min(this.top, region.top);
3012 var r = Math.max(this.right, region.right);
3013 var b = Math.max(this.bottom, region.bottom);
3014 var l = Math.min(this.left, region.left);
3016 return new Roo.lib.Region(t, r, b, l);
3019 adjust : function(t, l, b, r) {
3028 Roo.lib.Region.getRegion = function(el) {
3029 var p = Roo.lib.Dom.getXY(el);
3032 var r = p[0] + el.offsetWidth;
3033 var b = p[1] + el.offsetHeight;
3036 return new Roo.lib.Region(t, r, b, l);
3039 * Portions of this file are based on pieces of Yahoo User Interface Library
3040 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3041 * YUI licensed under the BSD License:
3042 * http://developer.yahoo.net/yui/license.txt
3043 * <script type="text/javascript">
3046 //@@dep Roo.lib.Region
3049 Roo.lib.Point = function(x, y) {
3050 if (x instanceof Array) {
3054 this.x = this.right = this.left = this[0] = x;
3055 this.y = this.top = this.bottom = this[1] = y;
3058 Roo.lib.Point.prototype = new Roo.lib.Region();
3060 * Portions of this file are based on pieces of Yahoo User Interface Library
3061 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3062 * YUI licensed under the BSD License:
3063 * http://developer.yahoo.net/yui/license.txt
3064 * <script type="text/javascript">
3071 scroll : function(el, args, duration, easing, cb, scope) {
3072 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3075 motion : function(el, args, duration, easing, cb, scope) {
3076 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3079 color : function(el, args, duration, easing, cb, scope) {
3080 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3083 run : function(el, args, duration, easing, cb, scope, type) {
3084 type = type || Roo.lib.AnimBase;
3085 if (typeof easing == "string") {
3086 easing = Roo.lib.Easing[easing];
3088 var anim = new type(el, args, duration, easing);
3089 anim.animateX(function() {
3090 Roo.callback(cb, scope);
3096 * Portions of this file are based on pieces of Yahoo User Interface Library
3097 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3098 * YUI licensed under the BSD License:
3099 * http://developer.yahoo.net/yui/license.txt
3100 * <script type="text/javascript">
3108 if (!libFlyweight) {
3109 libFlyweight = new Roo.Element.Flyweight();
3111 libFlyweight.dom = el;
3112 return libFlyweight;
3115 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3119 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3121 this.init(el, attributes, duration, method);
3125 Roo.lib.AnimBase.fly = fly;
3129 Roo.lib.AnimBase.prototype = {
3131 toString: function() {
3132 var el = this.getEl();
3133 var id = el.id || el.tagName;
3134 return ("Anim " + id);
3138 noNegatives: /width|height|opacity|padding/i,
3139 offsetAttribute: /^((width|height)|(top|left))$/,
3140 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3141 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3145 doMethod: function(attr, start, end) {
3146 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3150 setAttribute: function(attr, val, unit) {
3151 if (this.patterns.noNegatives.test(attr)) {
3152 val = (val > 0) ? val : 0;
3155 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3159 getAttribute: function(attr) {
3160 var el = this.getEl();
3161 var val = fly(el).getStyle(attr);
3163 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3164 return parseFloat(val);
3167 var a = this.patterns.offsetAttribute.exec(attr) || [];
3168 var pos = !!( a[3] );
3169 var box = !!( a[2] );
3172 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3173 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3182 getDefaultUnit: function(attr) {
3183 if (this.patterns.defaultUnit.test(attr)) {
3190 animateX : function(callback, scope) {
3191 var f = function() {
3192 this.onComplete.removeListener(f);
3193 if (typeof callback == "function") {
3194 callback.call(scope || this, this);
3197 this.onComplete.addListener(f, this);
3202 setRuntimeAttribute: function(attr) {
3205 var attributes = this.attributes;
3207 this.runtimeAttributes[attr] = {};
3209 var isset = function(prop) {
3210 return (typeof prop !== 'undefined');
3213 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3217 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3220 if (isset(attributes[attr]['to'])) {
3221 end = attributes[attr]['to'];
3222 } else if (isset(attributes[attr]['by'])) {
3223 if (start.constructor == Array) {
3225 for (var i = 0, len = start.length; i < len; ++i) {
3226 end[i] = start[i] + attributes[attr]['by'][i];
3229 end = start + attributes[attr]['by'];
3233 this.runtimeAttributes[attr].start = start;
3234 this.runtimeAttributes[attr].end = end;
3237 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3241 init: function(el, attributes, duration, method) {
3243 var isAnimated = false;
3246 var startTime = null;
3249 var actualFrames = 0;
3252 el = Roo.getDom(el);
3255 this.attributes = attributes || {};
3258 this.duration = duration || 1;
3261 this.method = method || Roo.lib.Easing.easeNone;
3264 this.useSeconds = true;
3267 this.currentFrame = 0;
3270 this.totalFrames = Roo.lib.AnimMgr.fps;
3273 this.getEl = function() {
3278 this.isAnimated = function() {
3283 this.getStartTime = function() {
3287 this.runtimeAttributes = {};
3290 this.animate = function() {
3291 if (this.isAnimated()) {
3295 this.currentFrame = 0;
3297 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3299 Roo.lib.AnimMgr.registerElement(this);
3303 this.stop = function(finish) {
3305 this.currentFrame = this.totalFrames;
3306 this._onTween.fire();
3308 Roo.lib.AnimMgr.stop(this);
3311 var onStart = function() {
3312 this.onStart.fire();
3314 this.runtimeAttributes = {};
3315 for (var attr in this.attributes) {
3316 this.setRuntimeAttribute(attr);
3321 startTime = new Date();
3325 var onTween = function() {
3327 duration: new Date() - this.getStartTime(),
3328 currentFrame: this.currentFrame
3331 data.toString = function() {
3333 'duration: ' + data.duration +
3334 ', currentFrame: ' + data.currentFrame
3338 this.onTween.fire(data);
3340 var runtimeAttributes = this.runtimeAttributes;
3342 for (var attr in runtimeAttributes) {
3343 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3349 var onComplete = function() {
3350 var actual_duration = (new Date() - startTime) / 1000 ;
3353 duration: actual_duration,
3354 frames: actualFrames,
3355 fps: actualFrames / actual_duration
3358 data.toString = function() {
3360 'duration: ' + data.duration +
3361 ', frames: ' + data.frames +
3362 ', fps: ' + data.fps
3368 this.onComplete.fire(data);
3372 this._onStart = new Roo.util.Event(this);
3373 this.onStart = new Roo.util.Event(this);
3374 this.onTween = new Roo.util.Event(this);
3375 this._onTween = new Roo.util.Event(this);
3376 this.onComplete = new Roo.util.Event(this);
3377 this._onComplete = new Roo.util.Event(this);
3378 this._onStart.addListener(onStart);
3379 this._onTween.addListener(onTween);
3380 this._onComplete.addListener(onComplete);
3385 * Portions of this file are based on pieces of Yahoo User Interface Library
3386 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3387 * YUI licensed under the BSD License:
3388 * http://developer.yahoo.net/yui/license.txt
3389 * <script type="text/javascript">
3393 Roo.lib.AnimMgr = new function() {
3410 this.registerElement = function(tween) {
3411 queue[queue.length] = tween;
3413 tween._onStart.fire();
3418 this.unRegister = function(tween, index) {
3419 tween._onComplete.fire();
3420 index = index || getIndex(tween);
3422 queue.splice(index, 1);
3426 if (tweenCount <= 0) {
3432 this.start = function() {
3433 if (thread === null) {
3434 thread = setInterval(this.run, this.delay);
3439 this.stop = function(tween) {
3441 clearInterval(thread);
3443 for (var i = 0, len = queue.length; i < len; ++i) {
3444 if (queue[0].isAnimated()) {
3445 this.unRegister(queue[0], 0);
3454 this.unRegister(tween);
3459 this.run = function() {
3460 for (var i = 0, len = queue.length; i < len; ++i) {
3461 var tween = queue[i];
3462 if (!tween || !tween.isAnimated()) {
3466 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3468 tween.currentFrame += 1;
3470 if (tween.useSeconds) {
3471 correctFrame(tween);
3473 tween._onTween.fire();
3476 Roo.lib.AnimMgr.stop(tween, i);
3481 var getIndex = function(anim) {
3482 for (var i = 0, len = queue.length; i < len; ++i) {
3483 if (queue[i] == anim) {
3491 var correctFrame = function(tween) {
3492 var frames = tween.totalFrames;
3493 var frame = tween.currentFrame;
3494 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3495 var elapsed = (new Date() - tween.getStartTime());
3498 if (elapsed < tween.duration * 1000) {
3499 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3501 tweak = frames - (frame + 1);
3503 if (tweak > 0 && isFinite(tweak)) {
3504 if (tween.currentFrame + tweak >= frames) {
3505 tweak = frames - (frame + 1);
3508 tween.currentFrame += tweak;
3512 * Portions of this file are based on pieces of Yahoo User Interface Library
3513 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3514 * YUI licensed under the BSD License:
3515 * http://developer.yahoo.net/yui/license.txt
3516 * <script type="text/javascript">
3519 Roo.lib.Bezier = new function() {
3521 this.getPosition = function(points, t) {
3522 var n = points.length;
3525 for (var i = 0; i < n; ++i) {
3526 tmp[i] = [points[i][0], points[i][1]];
3529 for (var j = 1; j < n; ++j) {
3530 for (i = 0; i < n - j; ++i) {
3531 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3532 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3536 return [ tmp[0][0], tmp[0][1] ];
3540 * Portions of this file are based on pieces of Yahoo User Interface Library
3541 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3542 * YUI licensed under the BSD License:
3543 * http://developer.yahoo.net/yui/license.txt
3544 * <script type="text/javascript">
3549 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3550 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3553 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3555 var fly = Roo.lib.AnimBase.fly;
3557 var superclass = Y.ColorAnim.superclass;
3558 var proto = Y.ColorAnim.prototype;
3560 proto.toString = function() {
3561 var el = this.getEl();
3562 var id = el.id || el.tagName;
3563 return ("ColorAnim " + id);
3566 proto.patterns.color = /color$/i;
3567 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3568 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3569 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3570 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3573 proto.parseColor = function(s) {
3574 if (s.length == 3) {
3578 var c = this.patterns.hex.exec(s);
3579 if (c && c.length == 4) {
3580 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3583 c = this.patterns.rgb.exec(s);
3584 if (c && c.length == 4) {
3585 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3588 c = this.patterns.hex3.exec(s);
3589 if (c && c.length == 4) {
3590 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3595 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3596 proto.getAttribute = function(attr) {
3597 var el = this.getEl();
3598 if (this.patterns.color.test(attr)) {
3599 var val = fly(el).getStyle(attr);
3601 if (this.patterns.transparent.test(val)) {
3602 var parent = el.parentNode;
3603 val = fly(parent).getStyle(attr);
3605 while (parent && this.patterns.transparent.test(val)) {
3606 parent = parent.parentNode;
3607 val = fly(parent).getStyle(attr);
3608 if (parent.tagName.toUpperCase() == 'HTML') {
3614 val = superclass.getAttribute.call(this, attr);
3619 proto.getAttribute = function(attr) {
3620 var el = this.getEl();
3621 if (this.patterns.color.test(attr)) {
3622 var val = fly(el).getStyle(attr);
3624 if (this.patterns.transparent.test(val)) {
3625 var parent = el.parentNode;
3626 val = fly(parent).getStyle(attr);
3628 while (parent && this.patterns.transparent.test(val)) {
3629 parent = parent.parentNode;
3630 val = fly(parent).getStyle(attr);
3631 if (parent.tagName.toUpperCase() == 'HTML') {
3637 val = superclass.getAttribute.call(this, attr);
3643 proto.doMethod = function(attr, start, end) {
3646 if (this.patterns.color.test(attr)) {
3648 for (var i = 0, len = start.length; i < len; ++i) {
3649 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3652 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3655 val = superclass.doMethod.call(this, attr, start, end);
3661 proto.setRuntimeAttribute = function(attr) {
3662 superclass.setRuntimeAttribute.call(this, attr);
3664 if (this.patterns.color.test(attr)) {
3665 var attributes = this.attributes;
3666 var start = this.parseColor(this.runtimeAttributes[attr].start);
3667 var end = this.parseColor(this.runtimeAttributes[attr].end);
3669 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3670 end = this.parseColor(attributes[attr].by);
3672 for (var i = 0, len = start.length; i < len; ++i) {
3673 end[i] = start[i] + end[i];
3677 this.runtimeAttributes[attr].start = start;
3678 this.runtimeAttributes[attr].end = end;
3684 * Portions of this file are based on pieces of Yahoo User Interface Library
3685 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3686 * YUI licensed under the BSD License:
3687 * http://developer.yahoo.net/yui/license.txt
3688 * <script type="text/javascript">
3694 easeNone: function (t, b, c, d) {
3695 return c * t / d + b;
3699 easeIn: function (t, b, c, d) {
3700 return c * (t /= d) * t + b;
3704 easeOut: function (t, b, c, d) {
3705 return -c * (t /= d) * (t - 2) + b;
3709 easeBoth: function (t, b, c, d) {
3710 if ((t /= d / 2) < 1) {
3711 return c / 2 * t * t + b;
3714 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3718 easeInStrong: function (t, b, c, d) {
3719 return c * (t /= d) * t * t * t + b;
3723 easeOutStrong: function (t, b, c, d) {
3724 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3728 easeBothStrong: function (t, b, c, d) {
3729 if ((t /= d / 2) < 1) {
3730 return c / 2 * t * t * t * t + b;
3733 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3738 elasticIn: function (t, b, c, d, a, p) {
3742 if ((t /= d) == 1) {
3749 if (!a || a < Math.abs(c)) {
3754 var s = p / (2 * Math.PI) * Math.asin(c / a);
3757 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3761 elasticOut: function (t, b, c, d, a, p) {
3765 if ((t /= d) == 1) {
3772 if (!a || a < Math.abs(c)) {
3777 var s = p / (2 * Math.PI) * Math.asin(c / a);
3780 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3784 elasticBoth: function (t, b, c, d, a, p) {
3789 if ((t /= d / 2) == 2) {
3797 if (!a || a < Math.abs(c)) {
3802 var s = p / (2 * Math.PI) * Math.asin(c / a);
3806 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3807 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3809 return a * Math.pow(2, -10 * (t -= 1)) *
3810 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3815 backIn: function (t, b, c, d, s) {
3816 if (typeof s == 'undefined') {
3819 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3823 backOut: function (t, b, c, d, s) {
3824 if (typeof s == 'undefined') {
3827 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3831 backBoth: function (t, b, c, d, s) {
3832 if (typeof s == 'undefined') {
3836 if ((t /= d / 2 ) < 1) {
3837 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3839 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3843 bounceIn: function (t, b, c, d) {
3844 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3848 bounceOut: function (t, b, c, d) {
3849 if ((t /= d) < (1 / 2.75)) {
3850 return c * (7.5625 * t * t) + b;
3851 } else if (t < (2 / 2.75)) {
3852 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3853 } else if (t < (2.5 / 2.75)) {
3854 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3856 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3860 bounceBoth: function (t, b, c, d) {
3862 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3864 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3867 * Portions of this file are based on pieces of Yahoo User Interface Library
3868 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3869 * YUI licensed under the BSD License:
3870 * http://developer.yahoo.net/yui/license.txt
3871 * <script type="text/javascript">
3875 Roo.lib.Motion = function(el, attributes, duration, method) {
3877 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3881 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3885 var superclass = Y.Motion.superclass;
3886 var proto = Y.Motion.prototype;
3888 proto.toString = function() {
3889 var el = this.getEl();
3890 var id = el.id || el.tagName;
3891 return ("Motion " + id);
3894 proto.patterns.points = /^points$/i;
3896 proto.setAttribute = function(attr, val, unit) {
3897 if (this.patterns.points.test(attr)) {
3898 unit = unit || 'px';
3899 superclass.setAttribute.call(this, 'left', val[0], unit);
3900 superclass.setAttribute.call(this, 'top', val[1], unit);
3902 superclass.setAttribute.call(this, attr, val, unit);
3906 proto.getAttribute = function(attr) {
3907 if (this.patterns.points.test(attr)) {
3909 superclass.getAttribute.call(this, 'left'),
3910 superclass.getAttribute.call(this, 'top')
3913 val = superclass.getAttribute.call(this, attr);
3919 proto.doMethod = function(attr, start, end) {
3922 if (this.patterns.points.test(attr)) {
3923 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3924 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3926 val = superclass.doMethod.call(this, attr, start, end);
3931 proto.setRuntimeAttribute = function(attr) {
3932 if (this.patterns.points.test(attr)) {
3933 var el = this.getEl();
3934 var attributes = this.attributes;
3936 var control = attributes['points']['control'] || [];
3940 if (control.length > 0 && !(control[0] instanceof Array)) {
3941 control = [control];
3944 for (i = 0,len = control.length; i < len; ++i) {
3945 tmp[i] = control[i];
3950 Roo.fly(el).position();
3952 if (isset(attributes['points']['from'])) {
3953 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3956 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3959 start = this.getAttribute('points');
3962 if (isset(attributes['points']['to'])) {
3963 end = translateValues.call(this, attributes['points']['to'], start);
3965 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3966 for (i = 0,len = control.length; i < len; ++i) {
3967 control[i] = translateValues.call(this, control[i], start);
3971 } else if (isset(attributes['points']['by'])) {
3972 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3974 for (i = 0,len = control.length; i < len; ++i) {
3975 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3979 this.runtimeAttributes[attr] = [start];
3981 if (control.length > 0) {
3982 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3985 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3988 superclass.setRuntimeAttribute.call(this, attr);
3992 var translateValues = function(val, start) {
3993 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3994 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3999 var isset = function(prop) {
4000 return (typeof prop !== 'undefined');
4004 * Portions of this file are based on pieces of Yahoo User Interface Library
4005 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4006 * YUI licensed under the BSD License:
4007 * http://developer.yahoo.net/yui/license.txt
4008 * <script type="text/javascript">
4012 Roo.lib.Scroll = function(el, attributes, duration, method) {
4014 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4018 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4022 var superclass = Y.Scroll.superclass;
4023 var proto = Y.Scroll.prototype;
4025 proto.toString = function() {
4026 var el = this.getEl();
4027 var id = el.id || el.tagName;
4028 return ("Scroll " + id);
4031 proto.doMethod = function(attr, start, end) {
4034 if (attr == 'scroll') {
4036 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4037 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4041 val = superclass.doMethod.call(this, attr, start, end);
4046 proto.getAttribute = function(attr) {
4048 var el = this.getEl();
4050 if (attr == 'scroll') {
4051 val = [ el.scrollLeft, el.scrollTop ];
4053 val = superclass.getAttribute.call(this, attr);
4059 proto.setAttribute = function(attr, val, unit) {
4060 var el = this.getEl();
4062 if (attr == 'scroll') {
4063 el.scrollLeft = val[0];
4064 el.scrollTop = val[1];
4066 superclass.setAttribute.call(this, attr, val, unit);
4072 * Ext JS Library 1.1.1
4073 * Copyright(c) 2006-2007, Ext JS, LLC.
4075 * Originally Released Under LGPL - original licence link has changed is not relivant.
4078 * <script type="text/javascript">
4082 // nasty IE9 hack - what a pile of crap that is..
4084 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4085 Range.prototype.createContextualFragment = function (html) {
4086 var doc = window.document;
4087 var container = doc.createElement("div");
4088 container.innerHTML = html;
4089 var frag = doc.createDocumentFragment(), n;
4090 while ((n = container.firstChild)) {
4091 frag.appendChild(n);
4098 * @class Roo.DomHelper
4099 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4100 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4103 Roo.DomHelper = function(){
4104 var tempTableEl = null;
4105 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4106 var tableRe = /^table|tbody|tr|td$/i;
4108 // build as innerHTML where available
4110 var createHtml = function(o){
4111 if(typeof o == 'string'){
4120 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4121 if(attr == "style"){
4123 if(typeof s == "function"){
4126 if(typeof s == "string"){
4127 b += ' style="' + s + '"';
4128 }else if(typeof s == "object"){
4131 if(typeof s[key] != "function"){
4132 b += key + ":" + s[key] + ";";
4139 b += ' class="' + o["cls"] + '"';
4140 }else if(attr == "htmlFor"){
4141 b += ' for="' + o["htmlFor"] + '"';
4143 b += " " + attr + '="' + o[attr] + '"';
4147 if(emptyTags.test(o.tag)){
4151 var cn = o.children || o.cn;
4153 //http://bugs.kde.org/show_bug.cgi?id=71506
4154 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4155 for(var i = 0, len = cn.length; i < len; i++) {
4156 b += createHtml(cn[i], b);
4159 b += createHtml(cn, b);
4165 b += "</" + o.tag + ">";
4172 var createDom = function(o, parentNode){
4174 // defininition craeted..
4176 if (o.ns && o.ns != 'html') {
4178 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4179 xmlns[o.ns] = o.xmlns;
4182 if (typeof(xmlns[o.ns]) == 'undefined') {
4183 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4189 if (typeof(o) == 'string') {
4190 return parentNode.appendChild(document.createTextNode(o));
4192 o.tag = o.tag || div;
4193 if (o.ns && Roo.isIE) {
4195 o.tag = o.ns + ':' + o.tag;
4198 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4199 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4202 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4203 attr == "style" || typeof o[attr] == "function") continue;
4205 if(attr=="cls" && Roo.isIE){
4206 el.className = o["cls"];
4208 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4209 else el[attr] = o[attr];
4212 Roo.DomHelper.applyStyles(el, o.style);
4213 var cn = o.children || o.cn;
4215 //http://bugs.kde.org/show_bug.cgi?id=71506
4216 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4217 for(var i = 0, len = cn.length; i < len; i++) {
4218 createDom(cn[i], el);
4225 el.innerHTML = o.html;
4228 parentNode.appendChild(el);
4233 var ieTable = function(depth, s, h, e){
4234 tempTableEl.innerHTML = [s, h, e].join('');
4235 var i = -1, el = tempTableEl;
4242 // kill repeat to save bytes
4246 tbe = '</tbody>'+te,
4252 * Nasty code for IE's broken table implementation
4254 var insertIntoTable = function(tag, where, el, html){
4256 tempTableEl = document.createElement('div');
4261 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4264 if(where == 'beforebegin'){
4268 before = el.nextSibling;
4271 node = ieTable(4, trs, html, tre);
4273 else if(tag == 'tr'){
4274 if(where == 'beforebegin'){
4277 node = ieTable(3, tbs, html, tbe);
4278 } else if(where == 'afterend'){
4279 before = el.nextSibling;
4281 node = ieTable(3, tbs, html, tbe);
4282 } else{ // INTO a TR
4283 if(where == 'afterbegin'){
4284 before = el.firstChild;
4286 node = ieTable(4, trs, html, tre);
4288 } else if(tag == 'tbody'){
4289 if(where == 'beforebegin'){
4292 node = ieTable(2, ts, html, te);
4293 } else if(where == 'afterend'){
4294 before = el.nextSibling;
4296 node = ieTable(2, ts, html, te);
4298 if(where == 'afterbegin'){
4299 before = el.firstChild;
4301 node = ieTable(3, tbs, html, tbe);
4304 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4307 if(where == 'afterbegin'){
4308 before = el.firstChild;
4310 node = ieTable(2, ts, html, te);
4312 el.insertBefore(node, before);
4317 /** True to force the use of DOM instead of html fragments @type Boolean */
4321 * Returns the markup for the passed Element(s) config
4322 * @param {Object} o The Dom object spec (and children)
4325 markup : function(o){
4326 return createHtml(o);
4330 * Applies a style specification to an element
4331 * @param {String/HTMLElement} el The element to apply styles to
4332 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4333 * a function which returns such a specification.
4335 applyStyles : function(el, styles){
4338 if(typeof styles == "string"){
4339 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4341 while ((matches = re.exec(styles)) != null){
4342 el.setStyle(matches[1], matches[2]);
4344 }else if (typeof styles == "object"){
4345 for (var style in styles){
4346 el.setStyle(style, styles[style]);
4348 }else if (typeof styles == "function"){
4349 Roo.DomHelper.applyStyles(el, styles.call());
4355 * Inserts an HTML fragment into the Dom
4356 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4357 * @param {HTMLElement} el The context element
4358 * @param {String} html The HTML fragmenet
4359 * @return {HTMLElement} The new node
4361 insertHtml : function(where, el, html){
4362 where = where.toLowerCase();
4363 if(el.insertAdjacentHTML){
4364 if(tableRe.test(el.tagName)){
4366 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4372 el.insertAdjacentHTML('BeforeBegin', html);
4373 return el.previousSibling;
4375 el.insertAdjacentHTML('AfterBegin', html);
4376 return el.firstChild;
4378 el.insertAdjacentHTML('BeforeEnd', html);
4379 return el.lastChild;
4381 el.insertAdjacentHTML('AfterEnd', html);
4382 return el.nextSibling;
4384 throw 'Illegal insertion point -> "' + where + '"';
4386 var range = el.ownerDocument.createRange();
4390 range.setStartBefore(el);
4391 frag = range.createContextualFragment(html);
4392 el.parentNode.insertBefore(frag, el);
4393 return el.previousSibling;
4396 range.setStartBefore(el.firstChild);
4397 frag = range.createContextualFragment(html);
4398 el.insertBefore(frag, el.firstChild);
4399 return el.firstChild;
4401 el.innerHTML = html;
4402 return el.firstChild;
4406 range.setStartAfter(el.lastChild);
4407 frag = range.createContextualFragment(html);
4408 el.appendChild(frag);
4409 return el.lastChild;
4411 el.innerHTML = html;
4412 return el.lastChild;
4415 range.setStartAfter(el);
4416 frag = range.createContextualFragment(html);
4417 el.parentNode.insertBefore(frag, el.nextSibling);
4418 return el.nextSibling;
4420 throw 'Illegal insertion point -> "' + where + '"';
4424 * Creates new Dom element(s) and inserts them before el
4425 * @param {String/HTMLElement/Element} el The context element
4426 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4427 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4428 * @return {HTMLElement/Roo.Element} The new node
4430 insertBefore : function(el, o, returnElement){
4431 return this.doInsert(el, o, returnElement, "beforeBegin");
4435 * Creates new Dom element(s) and inserts them after el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object} o The Dom object spec (and children)
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertAfter : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4446 * Creates new Dom element(s) and inserts them as the first child of el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertFirst : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterBegin");
4457 doInsert : function(el, o, returnElement, pos, sibling){
4458 el = Roo.getDom(el);
4460 if(this.useDom || o.ns){
4461 newNode = createDom(o, null);
4462 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4464 var html = createHtml(o);
4465 newNode = this.insertHtml(pos, el, html);
4467 return returnElement ? Roo.get(newNode, true) : newNode;
4471 * Creates new Dom element(s) and appends them to el
4472 * @param {String/HTMLElement/Element} el The context element
4473 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4474 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475 * @return {HTMLElement/Roo.Element} The new node
4477 append : function(el, o, returnElement){
4478 el = Roo.getDom(el);
4480 if(this.useDom || o.ns){
4481 newNode = createDom(o, null);
4482 el.appendChild(newNode);
4484 var html = createHtml(o);
4485 newNode = this.insertHtml("beforeEnd", el, html);
4487 return returnElement ? Roo.get(newNode, true) : newNode;
4491 * Creates new Dom element(s) and overwrites the contents of el with them
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 overwrite : function(el, o, returnElement){
4498 el = Roo.getDom(el);
4501 while (el.childNodes.length) {
4502 el.removeChild(el.firstChild);
4506 el.innerHTML = createHtml(o);
4509 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4513 * Creates a new Roo.DomHelper.Template from the Dom object spec
4514 * @param {Object} o The Dom object spec (and children)
4515 * @return {Roo.DomHelper.Template} The new template
4517 createTemplate : function(o){
4518 var html = createHtml(o);
4519 return new Roo.Template(html);
4525 * Ext JS Library 1.1.1
4526 * Copyright(c) 2006-2007, Ext JS, LLC.
4528 * Originally Released Under LGPL - original licence link has changed is not relivant.
4531 * <script type="text/javascript">
4535 * @class Roo.Template
4536 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4537 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4540 var t = new Roo.Template({
4541 html : '<div name="{id}">' +
4542 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4544 myformat: function (value, allValues) {
4545 return 'XX' + value;
4548 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4550 * For more information see this blog post with examples:
4551 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4552 - Create Elements using DOM, HTML fragments and Templates</a>.
4554 * @param {Object} cfg - Configuration object.
4556 Roo.Template = function(cfg){
4558 if(cfg instanceof Array){
4560 }else if(arguments.length > 1){
4561 cfg = Array.prototype.join.call(arguments, "");
4565 if (typeof(cfg) == 'object') {
4576 Roo.Template.prototype = {
4579 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4580 * it should be fixed so that template is observable...
4584 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4588 * Returns an HTML fragment of this template with the specified values applied.
4589 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4590 * @return {String} The HTML fragment
4592 applyTemplate : function(values){
4596 return this.compiled(values);
4598 var useF = this.disableFormats !== true;
4599 var fm = Roo.util.Format, tpl = this;
4600 var fn = function(m, name, format, args){
4602 if(format.substr(0, 5) == "this."){
4603 return tpl.call(format.substr(5), values[name], values);
4606 // quoted values are required for strings in compiled templates,
4607 // but for non compiled we need to strip them
4608 // quoted reversed for jsmin
4609 var re = /^\s*['"](.*)["']\s*$/;
4610 args = args.split(',');
4611 for(var i = 0, len = args.length; i < len; i++){
4612 args[i] = args[i].replace(re, "$1");
4614 args = [values[name]].concat(args);
4616 args = [values[name]];
4618 return fm[format].apply(fm, args);
4621 return values[name] !== undefined ? values[name] : "";
4624 return this.html.replace(this.re, fn);
4642 this.loading = true;
4643 this.compiled = false;
4645 var cx = new Roo.data.Connection();
4649 success : function (response) {
4651 _t.html = response.responseText;
4655 failure : function(response) {
4656 Roo.log("Template failed to load from " + url);
4663 * Sets the HTML used as the template and optionally compiles it.
4664 * @param {String} html
4665 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4666 * @return {Roo.Template} this
4668 set : function(html, compile){
4670 this.compiled = null;
4678 * True to disable format functions (defaults to false)
4681 disableFormats : false,
4684 * The regular expression used to match template variables
4688 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4691 * Compiles the template into an internal function, eliminating the RegEx overhead.
4692 * @return {Roo.Template} this
4694 compile : function(){
4695 var fm = Roo.util.Format;
4696 var useF = this.disableFormats !== true;
4697 var sep = Roo.isGecko ? "+" : ",";
4698 var fn = function(m, name, format, args){
4700 args = args ? ',' + args : "";
4701 if(format.substr(0, 5) != "this."){
4702 format = "fm." + format + '(';
4704 format = 'this.call("'+ format.substr(5) + '", ';
4708 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4710 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4713 // branched to use + in gecko and [].join() in others
4715 body = "this.compiled = function(values){ return '" +
4716 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4719 body = ["this.compiled = function(values){ return ['"];
4720 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4721 body.push("'].join('');};");
4722 body = body.join('');
4732 // private function used to call members
4733 call : function(fnName, value, allValues){
4734 return this[fnName](value, allValues);
4738 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4739 * @param {String/HTMLElement/Roo.Element} el The context element
4740 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4741 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4742 * @return {HTMLElement/Roo.Element} The new node or Element
4744 insertFirst: function(el, values, returnElement){
4745 return this.doInsert('afterBegin', el, values, returnElement);
4749 * Applies the supplied values to the template and inserts the new node(s) before el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertBefore: function(el, values, returnElement){
4756 return this.doInsert('beforeBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) after el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertAfter : function(el, values, returnElement){
4767 return this.doInsert('afterEnd', el, values, returnElement);
4771 * Applies the supplied values to the template and appends the new node(s) to el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 append : function(el, values, returnElement){
4778 return this.doInsert('beforeEnd', el, values, returnElement);
4781 doInsert : function(where, el, values, returnEl){
4782 el = Roo.getDom(el);
4783 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4784 return returnEl ? Roo.get(newNode, true) : newNode;
4788 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4789 * @param {String/HTMLElement/Roo.Element} el The context element
4790 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4791 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4792 * @return {HTMLElement/Roo.Element} The new node or Element
4794 overwrite : function(el, values, returnElement){
4795 el = Roo.getDom(el);
4796 el.innerHTML = this.applyTemplate(values);
4797 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4801 * Alias for {@link #applyTemplate}
4804 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4807 Roo.DomHelper.Template = Roo.Template;
4810 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4811 * @param {String/HTMLElement} el A DOM element or its id
4812 * @returns {Roo.Template} The created template
4815 Roo.Template.from = function(el){
4816 el = Roo.getDom(el);
4817 return new Roo.Template(el.value || el.innerHTML);
4820 * Ext JS Library 1.1.1
4821 * Copyright(c) 2006-2007, Ext JS, LLC.
4823 * Originally Released Under LGPL - original licence link has changed is not relivant.
4826 * <script type="text/javascript">
4831 * This is code is also distributed under MIT license for use
4832 * with jQuery and prototype JavaScript libraries.
4835 * @class Roo.DomQuery
4836 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4838 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4841 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4843 <h4>Element Selectors:</h4>
4845 <li> <b>*</b> any element</li>
4846 <li> <b>E</b> an element with the tag E</li>
4847 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4848 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4849 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4850 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4852 <h4>Attribute Selectors:</h4>
4853 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4855 <li> <b>E[foo]</b> has an attribute "foo"</li>
4856 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4857 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4858 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4859 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4860 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4861 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4863 <h4>Pseudo Classes:</h4>
4865 <li> <b>E:first-child</b> E is the first child of its parent</li>
4866 <li> <b>E:last-child</b> E is the last child of its parent</li>
4867 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4868 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4869 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4870 <li> <b>E:only-child</b> E is the only child of its parent</li>
4871 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4872 <li> <b>E:first</b> the first E in the resultset</li>
4873 <li> <b>E:last</b> the last E in the resultset</li>
4874 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4875 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4876 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4877 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4878 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4879 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4880 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4881 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4882 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4884 <h4>CSS Value Selectors:</h4>
4886 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4887 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4888 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4889 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4890 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4891 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4895 Roo.DomQuery = function(){
4896 var cache = {}, simpleCache = {}, valueCache = {};
4897 var nonSpace = /\S/;
4898 var trimRe = /^\s+|\s+$/g;
4899 var tplRe = /\{(\d+)\}/g;
4900 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4901 var tagTokenRe = /^(#)?([\w-\*]+)/;
4902 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4904 function child(p, index){
4906 var n = p.firstChild;
4908 if(n.nodeType == 1){
4919 while((n = n.nextSibling) && n.nodeType != 1);
4924 while((n = n.previousSibling) && n.nodeType != 1);
4928 function children(d){
4929 var n = d.firstChild, ni = -1;
4931 var nx = n.nextSibling;
4932 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4942 function byClassName(c, a, v){
4946 var r = [], ri = -1, cn;
4947 for(var i = 0, ci; ci = c[i]; i++){
4948 if((' '+ci.className+' ').indexOf(v) != -1){
4955 function attrValue(n, attr){
4956 if(!n.tagName && typeof n.length != "undefined"){
4965 if(attr == "class" || attr == "className"){
4968 return n.getAttribute(attr) || n[attr];
4972 function getNodes(ns, mode, tagName){
4973 var result = [], ri = -1, cs;
4977 tagName = tagName || "*";
4978 if(typeof ns.getElementsByTagName != "undefined"){
4982 for(var i = 0, ni; ni = ns[i]; i++){
4983 cs = ni.getElementsByTagName(tagName);
4984 for(var j = 0, ci; ci = cs[j]; j++){
4988 }else if(mode == "/" || mode == ">"){
4989 var utag = tagName.toUpperCase();
4990 for(var i = 0, ni, cn; ni = ns[i]; i++){
4991 cn = ni.children || ni.childNodes;
4992 for(var j = 0, cj; cj = cn[j]; j++){
4993 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4998 }else if(mode == "+"){
4999 var utag = tagName.toUpperCase();
5000 for(var i = 0, n; n = ns[i]; i++){
5001 while((n = n.nextSibling) && n.nodeType != 1);
5002 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5006 }else if(mode == "~"){
5007 for(var i = 0, n; n = ns[i]; i++){
5008 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5017 function concat(a, b){
5021 for(var i = 0, l = b.length; i < l; i++){
5027 function byTag(cs, tagName){
5028 if(cs.tagName || cs == document){
5034 var r = [], ri = -1;
5035 tagName = tagName.toLowerCase();
5036 for(var i = 0, ci; ci = cs[i]; i++){
5037 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5044 function byId(cs, attr, id){
5045 if(cs.tagName || cs == document){
5051 var r = [], ri = -1;
5052 for(var i = 0,ci; ci = cs[i]; i++){
5053 if(ci && ci.id == id){
5061 function byAttribute(cs, attr, value, op, custom){
5062 var r = [], ri = -1, st = custom=="{";
5063 var f = Roo.DomQuery.operators[op];
5064 for(var i = 0, ci; ci = cs[i]; i++){
5067 a = Roo.DomQuery.getStyle(ci, attr);
5069 else if(attr == "class" || attr == "className"){
5071 }else if(attr == "for"){
5073 }else if(attr == "href"){
5074 a = ci.getAttribute("href", 2);
5076 a = ci.getAttribute(attr);
5078 if((f && f(a, value)) || (!f && a)){
5085 function byPseudo(cs, name, value){
5086 return Roo.DomQuery.pseudos[name](cs, value);
5089 // This is for IE MSXML which does not support expandos.
5090 // IE runs the same speed using setAttribute, however FF slows way down
5091 // and Safari completely fails so they need to continue to use expandos.
5092 var isIE = window.ActiveXObject ? true : false;
5094 // this eval is stop the compressor from
5095 // renaming the variable to something shorter
5097 /** eval:var:batch */
5102 function nodupIEXml(cs){
5104 cs[0].setAttribute("_nodup", d);
5106 for(var i = 1, len = cs.length; i < len; i++){
5108 if(!c.getAttribute("_nodup") != d){
5109 c.setAttribute("_nodup", d);
5113 for(var i = 0, len = cs.length; i < len; i++){
5114 cs[i].removeAttribute("_nodup");
5123 var len = cs.length, c, i, r = cs, cj, ri = -1;
5124 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5127 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5128 return nodupIEXml(cs);
5132 for(i = 1; c = cs[i]; i++){
5137 for(var j = 0; j < i; j++){
5140 for(j = i+1; cj = cs[j]; j++){
5152 function quickDiffIEXml(c1, c2){
5154 for(var i = 0, len = c1.length; i < len; i++){
5155 c1[i].setAttribute("_qdiff", d);
5158 for(var i = 0, len = c2.length; i < len; i++){
5159 if(c2[i].getAttribute("_qdiff") != d){
5160 r[r.length] = c2[i];
5163 for(var i = 0, len = c1.length; i < len; i++){
5164 c1[i].removeAttribute("_qdiff");
5169 function quickDiff(c1, c2){
5170 var len1 = c1.length;
5174 if(isIE && c1[0].selectSingleNode){
5175 return quickDiffIEXml(c1, c2);
5178 for(var i = 0; i < len1; i++){
5182 for(var i = 0, len = c2.length; i < len; i++){
5183 if(c2[i]._qdiff != d){
5184 r[r.length] = c2[i];
5190 function quickId(ns, mode, root, id){
5192 var d = root.ownerDocument || root;
5193 return d.getElementById(id);
5195 ns = getNodes(ns, mode, "*");
5196 return byId(ns, null, id);
5200 getStyle : function(el, name){
5201 return Roo.fly(el).getStyle(name);
5204 * Compiles a selector/xpath query into a reusable function. The returned function
5205 * takes one parameter "root" (optional), which is the context node from where the query should start.
5206 * @param {String} selector The selector/xpath query
5207 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5208 * @return {Function}
5210 compile : function(path, type){
5211 type = type || "select";
5213 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5214 var q = path, mode, lq;
5215 var tk = Roo.DomQuery.matchers;
5216 var tklen = tk.length;
5219 // accept leading mode switch
5220 var lmode = q.match(modeRe);
5221 if(lmode && lmode[1]){
5222 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5223 q = q.replace(lmode[1], "");
5225 // strip leading slashes
5226 while(path.substr(0, 1)=="/"){
5227 path = path.substr(1);
5230 while(q && lq != q){
5232 var tm = q.match(tagTokenRe);
5233 if(type == "select"){
5236 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5238 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5240 q = q.replace(tm[0], "");
5241 }else if(q.substr(0, 1) != '@'){
5242 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5247 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5254 while(!(mm = q.match(modeRe))){
5255 var matched = false;
5256 for(var j = 0; j < tklen; j++){
5258 var m = q.match(t.re);
5260 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5263 q = q.replace(m[0], "");
5268 // prevent infinite loop on bad selector
5270 throw 'Error parsing selector, parsing failed at "' + q + '"';
5274 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5275 q = q.replace(mm[1], "");
5278 fn[fn.length] = "return nodup(n);\n}";
5281 * list of variables that need from compression as they are used by eval.
5291 * eval:var:byClassName
5293 * eval:var:byAttribute
5294 * eval:var:attrValue
5302 * Selects a group of elements.
5303 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5304 * @param {Node} root (optional) The start of the query (defaults to document).
5307 select : function(path, root, type){
5308 if(!root || root == document){
5311 if(typeof root == "string"){
5312 root = document.getElementById(root);
5314 var paths = path.split(",");
5316 for(var i = 0, len = paths.length; i < len; i++){
5317 var p = paths[i].replace(trimRe, "");
5319 cache[p] = Roo.DomQuery.compile(p);
5321 throw p + " is not a valid selector";
5324 var result = cache[p](root);
5325 if(result && result != document){
5326 results = results.concat(result);
5329 if(paths.length > 1){
5330 return nodup(results);
5336 * Selects a single element.
5337 * @param {String} selector The selector/xpath query
5338 * @param {Node} root (optional) The start of the query (defaults to document).
5341 selectNode : function(path, root){
5342 return Roo.DomQuery.select(path, root)[0];
5346 * Selects the value of a node, optionally replacing null with the defaultValue.
5347 * @param {String} selector The selector/xpath query
5348 * @param {Node} root (optional) The start of the query (defaults to document).
5349 * @param {String} defaultValue
5351 selectValue : function(path, root, defaultValue){
5352 path = path.replace(trimRe, "");
5353 if(!valueCache[path]){
5354 valueCache[path] = Roo.DomQuery.compile(path, "select");
5356 var n = valueCache[path](root);
5357 n = n[0] ? n[0] : n;
5358 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5359 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5363 * Selects the value of a node, parsing integers and floats.
5364 * @param {String} selector The selector/xpath query
5365 * @param {Node} root (optional) The start of the query (defaults to document).
5366 * @param {Number} defaultValue
5369 selectNumber : function(path, root, defaultValue){
5370 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5371 return parseFloat(v);
5375 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5376 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5377 * @param {String} selector The simple selector to test
5380 is : function(el, ss){
5381 if(typeof el == "string"){
5382 el = document.getElementById(el);
5384 var isArray = (el instanceof Array);
5385 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5386 return isArray ? (result.length == el.length) : (result.length > 0);
5390 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5391 * @param {Array} el An array of elements to filter
5392 * @param {String} selector The simple selector to test
5393 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5394 * the selector instead of the ones that match
5397 filter : function(els, ss, nonMatches){
5398 ss = ss.replace(trimRe, "");
5399 if(!simpleCache[ss]){
5400 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5402 var result = simpleCache[ss](els);
5403 return nonMatches ? quickDiff(result, els) : result;
5407 * Collection of matching regular expressions and code snippets.
5411 select: 'n = byClassName(n, null, " {1} ");'
5413 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5414 select: 'n = byPseudo(n, "{1}", "{2}");'
5416 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5417 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5420 select: 'n = byId(n, null, "{1}");'
5423 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5428 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5429 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5432 "=" : function(a, v){
5435 "!=" : function(a, v){
5438 "^=" : function(a, v){
5439 return a && a.substr(0, v.length) == v;
5441 "$=" : function(a, v){
5442 return a && a.substr(a.length-v.length) == v;
5444 "*=" : function(a, v){
5445 return a && a.indexOf(v) !== -1;
5447 "%=" : function(a, v){
5448 return (a % v) == 0;
5450 "|=" : function(a, v){
5451 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5453 "~=" : function(a, v){
5454 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5459 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5460 * and the argument (if any) supplied in the selector.
5463 "first-child" : function(c){
5464 var r = [], ri = -1, n;
5465 for(var i = 0, ci; ci = n = c[i]; i++){
5466 while((n = n.previousSibling) && n.nodeType != 1);
5474 "last-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.nextSibling) && n.nodeType != 1);
5485 "nth-child" : function(c, a) {
5486 var r = [], ri = -1;
5487 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5488 var f = (m[1] || 1) - 0, l = m[2] - 0;
5489 for(var i = 0, n; n = c[i]; i++){
5490 var pn = n.parentNode;
5491 if (batch != pn._batch) {
5493 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5494 if(cn.nodeType == 1){
5501 if (l == 0 || n.nodeIndex == l){
5504 } else if ((n.nodeIndex + l) % f == 0){
5512 "only-child" : function(c){
5513 var r = [], ri = -1;;
5514 for(var i = 0, ci; ci = c[i]; i++){
5515 if(!prev(ci) && !next(ci)){
5522 "empty" : function(c){
5523 var r = [], ri = -1;
5524 for(var i = 0, ci; ci = c[i]; i++){
5525 var cns = ci.childNodes, j = 0, cn, empty = true;
5528 if(cn.nodeType == 1 || cn.nodeType == 3){
5540 "contains" : function(c, v){
5541 var r = [], ri = -1;
5542 for(var i = 0, ci; ci = c[i]; i++){
5543 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5550 "nodeValue" : function(c, v){
5551 var r = [], ri = -1;
5552 for(var i = 0, ci; ci = c[i]; i++){
5553 if(ci.firstChild && ci.firstChild.nodeValue == v){
5560 "checked" : function(c){
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5563 if(ci.checked == true){
5570 "not" : function(c, ss){
5571 return Roo.DomQuery.filter(c, ss, true);
5574 "odd" : function(c){
5575 return this["nth-child"](c, "odd");
5578 "even" : function(c){
5579 return this["nth-child"](c, "even");
5582 "nth" : function(c, a){
5583 return c[a-1] || [];
5586 "first" : function(c){
5590 "last" : function(c){
5591 return c[c.length-1] || [];
5594 "has" : function(c, ss){
5595 var s = Roo.DomQuery.select;
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(s(ss, ci).length > 0){
5605 "next" : function(c, ss){
5606 var is = Roo.DomQuery.is;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5617 "prev" : function(c, ss){
5618 var is = Roo.DomQuery.is;
5619 var r = [], ri = -1;
5620 for(var i = 0, ci; ci = c[i]; i++){
5633 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5634 * @param {String} path The selector/xpath query
5635 * @param {Node} root (optional) The start of the query (defaults to document).
5640 Roo.query = Roo.DomQuery.select;
5643 * Ext JS Library 1.1.1
5644 * Copyright(c) 2006-2007, Ext JS, LLC.
5646 * Originally Released Under LGPL - original licence link has changed is not relivant.
5649 * <script type="text/javascript">
5653 * @class Roo.util.Observable
5654 * Base class that provides a common interface for publishing events. Subclasses are expected to
5655 * to have a property "events" with all the events defined.<br>
5658 Employee = function(name){
5665 Roo.extend(Employee, Roo.util.Observable);
5667 * @param {Object} config properties to use (incuding events / listeners)
5670 Roo.util.Observable = function(cfg){
5673 this.addEvents(cfg.events || {});
5675 delete cfg.events; // make sure
5678 Roo.apply(this, cfg);
5681 this.on(this.listeners);
5682 delete this.listeners;
5685 Roo.util.Observable.prototype = {
5687 * @cfg {Object} listeners list of events and functions to call for this object,
5691 'click' : function(e) {
5701 * Fires the specified event with the passed parameters (minus the event name).
5702 * @param {String} eventName
5703 * @param {Object...} args Variable number of parameters are passed to handlers
5704 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5706 fireEvent : function(){
5707 var ce = this.events[arguments[0].toLowerCase()];
5708 if(typeof ce == "object"){
5709 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5716 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5719 * Appends an event handler to this component
5720 * @param {String} eventName The type of event to listen for
5721 * @param {Function} handler The method the event invokes
5722 * @param {Object} scope (optional) The scope in which to execute the handler
5723 * function. The handler function's "this" context.
5724 * @param {Object} options (optional) An object containing handler configuration
5725 * properties. This may contain any of the following properties:<ul>
5726 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5727 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5728 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5729 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5730 * by the specified number of milliseconds. If the event fires again within that time, the original
5731 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5734 * <b>Combining Options</b><br>
5735 * Using the options argument, it is possible to combine different types of listeners:<br>
5737 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5739 el.on('click', this.onClick, this, {
5746 * <b>Attaching multiple handlers in 1 call</b><br>
5747 * The method also allows for a single argument to be passed which is a config object containing properties
5748 * which specify multiple handlers.
5757 fn: this.onMouseOver,
5761 fn: this.onMouseOut,
5767 * Or a shorthand syntax which passes the same scope object to all handlers:
5770 'click': this.onClick,
5771 'mouseover': this.onMouseOver,
5772 'mouseout': this.onMouseOut,
5777 addListener : function(eventName, fn, scope, o){
5778 if(typeof eventName == "object"){
5781 if(this.filterOptRe.test(e)){
5784 if(typeof o[e] == "function"){
5786 this.addListener(e, o[e], o.scope, o);
5788 // individual options
5789 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5794 o = (!o || typeof o == "boolean") ? {} : o;
5795 eventName = eventName.toLowerCase();
5796 var ce = this.events[eventName] || true;
5797 if(typeof ce == "boolean"){
5798 ce = new Roo.util.Event(this, eventName);
5799 this.events[eventName] = ce;
5801 ce.addListener(fn, scope, o);
5805 * Removes a listener
5806 * @param {String} eventName The type of event to listen for
5807 * @param {Function} handler The handler to remove
5808 * @param {Object} scope (optional) The scope (this object) for the handler
5810 removeListener : function(eventName, fn, scope){
5811 var ce = this.events[eventName.toLowerCase()];
5812 if(typeof ce == "object"){
5813 ce.removeListener(fn, scope);
5818 * Removes all listeners for this object
5820 purgeListeners : function(){
5821 for(var evt in this.events){
5822 if(typeof this.events[evt] == "object"){
5823 this.events[evt].clearListeners();
5828 relayEvents : function(o, events){
5829 var createHandler = function(ename){
5831 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5834 for(var i = 0, len = events.length; i < len; i++){
5835 var ename = events[i];
5836 if(!this.events[ename]){ this.events[ename] = true; };
5837 o.on(ename, createHandler(ename), this);
5842 * Used to define events on this Observable
5843 * @param {Object} object The object with the events defined
5845 addEvents : function(o){
5849 Roo.applyIf(this.events, o);
5853 * Checks to see if this object has any listeners for a specified event
5854 * @param {String} eventName The name of the event to check for
5855 * @return {Boolean} True if the event is being listened for, else false
5857 hasListener : function(eventName){
5858 var e = this.events[eventName];
5859 return typeof e == "object" && e.listeners.length > 0;
5863 * Appends an event handler to this element (shorthand for addListener)
5864 * @param {String} eventName The type of event to listen for
5865 * @param {Function} handler The method the event invokes
5866 * @param {Object} scope (optional) The scope in which to execute the handler
5867 * function. The handler function's "this" context.
5868 * @param {Object} options (optional)
5871 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5873 * Removes a listener (shorthand for removeListener)
5874 * @param {String} eventName The type of event to listen for
5875 * @param {Function} handler The handler to remove
5876 * @param {Object} scope (optional) The scope (this object) for the handler
5879 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5882 * Starts capture on the specified Observable. All events will be passed
5883 * to the supplied function with the event name + standard signature of the event
5884 * <b>before</b> the event is fired. If the supplied function returns false,
5885 * the event will not fire.
5886 * @param {Observable} o The Observable to capture
5887 * @param {Function} fn The function to call
5888 * @param {Object} scope (optional) The scope (this object) for the fn
5891 Roo.util.Observable.capture = function(o, fn, scope){
5892 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5896 * Removes <b>all</b> added captures from the Observable.
5897 * @param {Observable} o The Observable to release
5900 Roo.util.Observable.releaseCapture = function(o){
5901 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5906 var createBuffered = function(h, o, scope){
5907 var task = new Roo.util.DelayedTask();
5909 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5913 var createSingle = function(h, e, fn, scope){
5915 e.removeListener(fn, scope);
5916 return h.apply(scope, arguments);
5920 var createDelayed = function(h, o, scope){
5922 var args = Array.prototype.slice.call(arguments, 0);
5923 setTimeout(function(){
5924 h.apply(scope, args);
5929 Roo.util.Event = function(obj, name){
5932 this.listeners = [];
5935 Roo.util.Event.prototype = {
5936 addListener : function(fn, scope, options){
5937 var o = options || {};
5938 scope = scope || this.obj;
5939 if(!this.isListening(fn, scope)){
5940 var l = {fn: fn, scope: scope, options: o};
5943 h = createDelayed(h, o, scope);
5946 h = createSingle(h, this, fn, scope);
5949 h = createBuffered(h, o, scope);
5952 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5953 this.listeners.push(l);
5955 this.listeners = this.listeners.slice(0);
5956 this.listeners.push(l);
5961 findListener : function(fn, scope){
5962 scope = scope || this.obj;
5963 var ls = this.listeners;
5964 for(var i = 0, len = ls.length; i < len; i++){
5966 if(l.fn == fn && l.scope == scope){
5973 isListening : function(fn, scope){
5974 return this.findListener(fn, scope) != -1;
5977 removeListener : function(fn, scope){
5979 if((index = this.findListener(fn, scope)) != -1){
5981 this.listeners.splice(index, 1);
5983 this.listeners = this.listeners.slice(0);
5984 this.listeners.splice(index, 1);
5991 clearListeners : function(){
5992 this.listeners = [];
5996 var ls = this.listeners, scope, len = ls.length;
5999 var args = Array.prototype.slice.call(arguments, 0);
6000 for(var i = 0; i < len; i++){
6002 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6003 this.firing = false;
6007 this.firing = false;
6014 * Ext JS Library 1.1.1
6015 * Copyright(c) 2006-2007, Ext JS, LLC.
6017 * Originally Released Under LGPL - original licence link has changed is not relivant.
6020 * <script type="text/javascript">
6024 * @class Roo.EventManager
6025 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6026 * several useful events directly.
6027 * See {@link Roo.EventObject} for more details on normalized event objects.
6030 Roo.EventManager = function(){
6031 var docReadyEvent, docReadyProcId, docReadyState = false;
6032 var resizeEvent, resizeTask, textEvent, textSize;
6033 var E = Roo.lib.Event;
6034 var D = Roo.lib.Dom;
6037 var fireDocReady = function(){
6039 docReadyState = true;
6042 clearInterval(docReadyProcId);
6044 if(Roo.isGecko || Roo.isOpera) {
6045 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6048 var defer = document.getElementById("ie-deferred-loader");
6050 defer.onreadystatechange = null;
6051 defer.parentNode.removeChild(defer);
6055 docReadyEvent.fire();
6056 docReadyEvent.clearListeners();
6061 var initDocReady = function(){
6062 docReadyEvent = new Roo.util.Event();
6063 if(Roo.isGecko || Roo.isOpera) {
6064 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6066 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6067 var defer = document.getElementById("ie-deferred-loader");
6068 defer.onreadystatechange = function(){
6069 if(this.readyState == "complete"){
6073 }else if(Roo.isSafari){
6074 docReadyProcId = setInterval(function(){
6075 var rs = document.readyState;
6076 if(rs == "complete") {
6081 // no matter what, make sure it fires on load
6082 E.on(window, "load", fireDocReady);
6085 var createBuffered = function(h, o){
6086 var task = new Roo.util.DelayedTask(h);
6088 // create new event object impl so new events don't wipe out properties
6089 e = new Roo.EventObjectImpl(e);
6090 task.delay(o.buffer, h, null, [e]);
6094 var createSingle = function(h, el, ename, fn){
6096 Roo.EventManager.removeListener(el, ename, fn);
6101 var createDelayed = function(h, o){
6103 // create new event object impl so new events don't wipe out properties
6104 e = new Roo.EventObjectImpl(e);
6105 setTimeout(function(){
6111 var listen = function(element, ename, opt, fn, scope){
6112 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6113 fn = fn || o.fn; scope = scope || o.scope;
6114 var el = Roo.getDom(element);
6116 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6118 var h = function(e){
6119 e = Roo.EventObject.setEvent(e);
6122 t = e.getTarget(o.delegate, el);
6129 if(o.stopEvent === true){
6132 if(o.preventDefault === true){
6135 if(o.stopPropagation === true){
6136 e.stopPropagation();
6139 if(o.normalized === false){
6143 fn.call(scope || el, e, t, o);
6146 h = createDelayed(h, o);
6149 h = createSingle(h, el, ename, fn);
6152 h = createBuffered(h, o);
6154 fn._handlers = fn._handlers || [];
6155 fn._handlers.push([Roo.id(el), ename, h]);
6158 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6159 el.addEventListener("DOMMouseScroll", h, false);
6160 E.on(window, 'unload', function(){
6161 el.removeEventListener("DOMMouseScroll", h, false);
6164 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6165 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6170 var stopListening = function(el, ename, fn){
6171 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6173 for(var i = 0, len = hds.length; i < len; i++){
6175 if(h[0] == id && h[1] == ename){
6182 E.un(el, ename, hd);
6183 el = Roo.getDom(el);
6184 if(ename == "mousewheel" && el.addEventListener){
6185 el.removeEventListener("DOMMouseScroll", hd, false);
6187 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6188 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6192 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6199 * @scope Roo.EventManager
6204 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6205 * object with a Roo.EventObject
6206 * @param {Function} fn The method the event invokes
6207 * @param {Object} scope An object that becomes the scope of the handler
6208 * @param {boolean} override If true, the obj passed in becomes
6209 * the execution scope of the listener
6210 * @return {Function} The wrapped function
6213 wrap : function(fn, scope, override){
6215 Roo.EventObject.setEvent(e);
6216 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6221 * Appends an event handler to an element (shorthand for addListener)
6222 * @param {String/HTMLElement} element The html element or id to assign the
6223 * @param {String} eventName The type of event to listen for
6224 * @param {Function} handler The method the event invokes
6225 * @param {Object} scope (optional) The scope in which to execute the handler
6226 * function. The handler function's "this" context.
6227 * @param {Object} options (optional) An object containing handler configuration
6228 * properties. This may contain any of the following properties:<ul>
6229 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6230 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6231 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6232 * <li>preventDefault {Boolean} True to prevent the default action</li>
6233 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6234 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6235 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6236 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6237 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6238 * by the specified number of milliseconds. If the event fires again within that time, the original
6239 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6242 * <b>Combining Options</b><br>
6243 * Using the options argument, it is possible to combine different types of listeners:<br>
6245 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6247 el.on('click', this.onClick, this, {
6254 * <b>Attaching multiple handlers in 1 call</b><br>
6255 * The method also allows for a single argument to be passed which is a config object containing properties
6256 * which specify multiple handlers.
6266 fn: this.onMouseOver
6275 * Or a shorthand syntax:<br>
6278 'click' : this.onClick,
6279 'mouseover' : this.onMouseOver,
6280 'mouseout' : this.onMouseOut
6284 addListener : function(element, eventName, fn, scope, options){
6285 if(typeof eventName == "object"){
6291 if(typeof o[e] == "function"){
6293 listen(element, e, o, o[e], o.scope);
6295 // individual options
6296 listen(element, e, o[e]);
6301 return listen(element, eventName, options, fn, scope);
6305 * Removes an event handler
6307 * @param {String/HTMLElement} element The id or html element to remove the
6309 * @param {String} eventName The type of event
6310 * @param {Function} fn
6311 * @return {Boolean} True if a listener was actually removed
6313 removeListener : function(element, eventName, fn){
6314 return stopListening(element, eventName, fn);
6318 * Fires when the document is ready (before onload and before images are loaded). Can be
6319 * accessed shorthanded Roo.onReady().
6320 * @param {Function} fn The method the event invokes
6321 * @param {Object} scope An object that becomes the scope of the handler
6322 * @param {boolean} options
6324 onDocumentReady : function(fn, scope, options){
6325 if(docReadyState){ // if it already fired
6326 docReadyEvent.addListener(fn, scope, options);
6327 docReadyEvent.fire();
6328 docReadyEvent.clearListeners();
6334 docReadyEvent.addListener(fn, scope, options);
6338 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6339 * @param {Function} fn The method the event invokes
6340 * @param {Object} scope An object that becomes the scope of the handler
6341 * @param {boolean} options
6343 onWindowResize : function(fn, scope, options){
6345 resizeEvent = new Roo.util.Event();
6346 resizeTask = new Roo.util.DelayedTask(function(){
6347 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6349 E.on(window, "resize", function(){
6351 resizeTask.delay(50);
6353 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6357 resizeEvent.addListener(fn, scope, options);
6361 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6362 * @param {Function} fn The method the event invokes
6363 * @param {Object} scope An object that becomes the scope of the handler
6364 * @param {boolean} options
6366 onTextResize : function(fn, scope, options){
6368 textEvent = new Roo.util.Event();
6369 var textEl = new Roo.Element(document.createElement('div'));
6370 textEl.dom.className = 'x-text-resize';
6371 textEl.dom.innerHTML = 'X';
6372 textEl.appendTo(document.body);
6373 textSize = textEl.dom.offsetHeight;
6374 setInterval(function(){
6375 if(textEl.dom.offsetHeight != textSize){
6376 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6378 }, this.textResizeInterval);
6380 textEvent.addListener(fn, scope, options);
6384 * Removes the passed window resize listener.
6385 * @param {Function} fn The method the event invokes
6386 * @param {Object} scope The scope of handler
6388 removeResizeListener : function(fn, scope){
6390 resizeEvent.removeListener(fn, scope);
6395 fireResize : function(){
6397 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6401 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6405 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6407 textResizeInterval : 50
6412 * @scopeAlias pub=Roo.EventManager
6416 * Appends an event handler to an element (shorthand for addListener)
6417 * @param {String/HTMLElement} element The html element or id to assign the
6418 * @param {String} eventName The type of event to listen for
6419 * @param {Function} handler The method the event invokes
6420 * @param {Object} scope (optional) The scope in which to execute the handler
6421 * function. The handler function's "this" context.
6422 * @param {Object} options (optional) An object containing handler configuration
6423 * properties. This may contain any of the following properties:<ul>
6424 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6425 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6426 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6427 * <li>preventDefault {Boolean} True to prevent the default action</li>
6428 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6429 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6430 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6431 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6432 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6433 * by the specified number of milliseconds. If the event fires again within that time, the original
6434 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6437 * <b>Combining Options</b><br>
6438 * Using the options argument, it is possible to combine different types of listeners:<br>
6440 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6442 el.on('click', this.onClick, this, {
6449 * <b>Attaching multiple handlers in 1 call</b><br>
6450 * The method also allows for a single argument to be passed which is a config object containing properties
6451 * which specify multiple handlers.
6461 fn: this.onMouseOver
6470 * Or a shorthand syntax:<br>
6473 'click' : this.onClick,
6474 'mouseover' : this.onMouseOver,
6475 'mouseout' : this.onMouseOut
6479 pub.on = pub.addListener;
6480 pub.un = pub.removeListener;
6482 pub.stoppedMouseDownEvent = new Roo.util.Event();
6486 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6487 * @param {Function} fn The method the event invokes
6488 * @param {Object} scope An object that becomes the scope of the handler
6489 * @param {boolean} override If true, the obj passed in becomes
6490 * the execution scope of the listener
6494 Roo.onReady = Roo.EventManager.onDocumentReady;
6496 Roo.onReady(function(){
6497 var bd = Roo.get(document.body);
6502 : Roo.isGecko ? "roo-gecko"
6503 : Roo.isOpera ? "roo-opera"
6504 : Roo.isSafari ? "roo-safari" : ""];
6507 cls.push("roo-mac");
6510 cls.push("roo-linux");
6512 if(Roo.isBorderBox){
6513 cls.push('roo-border-box');
6515 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6516 var p = bd.dom.parentNode;
6518 p.className += ' roo-strict';
6521 bd.addClass(cls.join(' '));
6525 * @class Roo.EventObject
6526 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6527 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6530 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6532 var target = e.getTarget();
6535 var myDiv = Roo.get("myDiv");
6536 myDiv.on("click", handleClick);
6538 Roo.EventManager.on("myDiv", 'click', handleClick);
6539 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6543 Roo.EventObject = function(){
6545 var E = Roo.lib.Event;
6547 // safari keypress events for special keys return bad keycodes
6550 63235 : 39, // right
6553 63276 : 33, // page up
6554 63277 : 34, // page down
6555 63272 : 46, // delete
6560 // normalize button clicks
6561 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6562 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6564 Roo.EventObjectImpl = function(e){
6566 this.setEvent(e.browserEvent || e);
6569 Roo.EventObjectImpl.prototype = {
6571 * Used to fix doc tools.
6572 * @scope Roo.EventObject.prototype
6578 /** The normal browser event */
6579 browserEvent : null,
6580 /** The button pressed in a mouse event */
6582 /** True if the shift key was down during the event */
6584 /** True if the control key was down during the event */
6586 /** True if the alt key was down during the event */
6645 setEvent : function(e){
6646 if(e == this || (e && e.browserEvent)){ // already wrapped
6649 this.browserEvent = e;
6651 // normalize buttons
6652 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6653 if(e.type == 'click' && this.button == -1){
6657 this.shiftKey = e.shiftKey;
6658 // mac metaKey behaves like ctrlKey
6659 this.ctrlKey = e.ctrlKey || e.metaKey;
6660 this.altKey = e.altKey;
6661 // in getKey these will be normalized for the mac
6662 this.keyCode = e.keyCode;
6663 // keyup warnings on firefox.
6664 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6665 // cache the target for the delayed and or buffered events
6666 this.target = E.getTarget(e);
6668 this.xy = E.getXY(e);
6671 this.shiftKey = false;
6672 this.ctrlKey = false;
6673 this.altKey = false;
6683 * Stop the event (preventDefault and stopPropagation)
6685 stopEvent : function(){
6686 if(this.browserEvent){
6687 if(this.browserEvent.type == 'mousedown'){
6688 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6690 E.stopEvent(this.browserEvent);
6695 * Prevents the browsers default handling of the event.
6697 preventDefault : function(){
6698 if(this.browserEvent){
6699 E.preventDefault(this.browserEvent);
6704 isNavKeyPress : function(){
6705 var k = this.keyCode;
6706 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6707 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6710 isSpecialKey : function(){
6711 var k = this.keyCode;
6712 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6713 (k == 16) || (k == 17) ||
6714 (k >= 18 && k <= 20) ||
6715 (k >= 33 && k <= 35) ||
6716 (k >= 36 && k <= 39) ||
6717 (k >= 44 && k <= 45);
6720 * Cancels bubbling of the event.
6722 stopPropagation : function(){
6723 if(this.browserEvent){
6724 if(this.type == 'mousedown'){
6725 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6727 E.stopPropagation(this.browserEvent);
6732 * Gets the key code for the event.
6735 getCharCode : function(){
6736 return this.charCode || this.keyCode;
6740 * Returns a normalized keyCode for the event.
6741 * @return {Number} The key code
6743 getKey : function(){
6744 var k = this.keyCode || this.charCode;
6745 return Roo.isSafari ? (safariKeys[k] || k) : k;
6749 * Gets the x coordinate of the event.
6752 getPageX : function(){
6757 * Gets the y coordinate of the event.
6760 getPageY : function(){
6765 * Gets the time of the event.
6768 getTime : function(){
6769 if(this.browserEvent){
6770 return E.getTime(this.browserEvent);
6776 * Gets the page coordinates of the event.
6777 * @return {Array} The xy values like [x, y]
6784 * Gets the target for the event.
6785 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6786 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6787 search as a number or element (defaults to 10 || document.body)
6788 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6789 * @return {HTMLelement}
6791 getTarget : function(selector, maxDepth, returnEl){
6792 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6795 * Gets the related target.
6796 * @return {HTMLElement}
6798 getRelatedTarget : function(){
6799 if(this.browserEvent){
6800 return E.getRelatedTarget(this.browserEvent);
6806 * Normalizes mouse wheel delta across browsers
6807 * @return {Number} The delta
6809 getWheelDelta : function(){
6810 var e = this.browserEvent;
6812 if(e.wheelDelta){ /* IE/Opera. */
6813 delta = e.wheelDelta/120;
6814 }else if(e.detail){ /* Mozilla case. */
6815 delta = -e.detail/3;
6821 * Returns true if the control, meta, shift or alt key was pressed during this event.
6824 hasModifier : function(){
6825 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6829 * Returns true if the target of this event equals el or is a child of el
6830 * @param {String/HTMLElement/Element} el
6831 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6834 within : function(el, related){
6835 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6836 return t && Roo.fly(el).contains(t);
6839 getPoint : function(){
6840 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6844 return new Roo.EventObjectImpl();
6849 * Ext JS Library 1.1.1
6850 * Copyright(c) 2006-2007, Ext JS, LLC.
6852 * Originally Released Under LGPL - original licence link has changed is not relivant.
6855 * <script type="text/javascript">
6859 // was in Composite Element!??!?!
6862 var D = Roo.lib.Dom;
6863 var E = Roo.lib.Event;
6864 var A = Roo.lib.Anim;
6866 // local style camelizing for speed
6868 var camelRe = /(-[a-z])/gi;
6869 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6870 var view = document.defaultView;
6873 * @class Roo.Element
6874 * Represents an Element in the DOM.<br><br>
6877 var el = Roo.get("my-div");
6880 var el = getEl("my-div");
6882 // or with a DOM element
6883 var el = Roo.get(myDivElement);
6885 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6886 * each call instead of constructing a new one.<br><br>
6887 * <b>Animations</b><br />
6888 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6889 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6891 Option Default Description
6892 --------- -------- ---------------------------------------------
6893 duration .35 The duration of the animation in seconds
6894 easing easeOut The YUI easing method
6895 callback none A function to execute when the anim completes
6896 scope this The scope (this) of the callback function
6898 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6899 * manipulate the animation. Here's an example:
6901 var el = Roo.get("my-div");
6906 // default animation
6907 el.setWidth(100, true);
6909 // animation with some options set
6916 // using the "anim" property to get the Anim object
6922 el.setWidth(100, opt);
6924 if(opt.anim.isAnimated()){
6928 * <b> Composite (Collections of) Elements</b><br />
6929 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6930 * @constructor Create a new Element directly.
6931 * @param {String/HTMLElement} element
6932 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6934 Roo.Element = function(element, forceNew){
6935 var dom = typeof element == "string" ?
6936 document.getElementById(element) : element;
6937 if(!dom){ // invalid id/element
6941 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6942 return Roo.Element.cache[id];
6952 * The DOM element ID
6955 this.id = id || Roo.id(dom);
6958 var El = Roo.Element;
6962 * The element's default display mode (defaults to "")
6965 originalDisplay : "",
6969 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6974 * Sets the element's visibility mode. When setVisible() is called it
6975 * will use this to determine whether to set the visibility or the display property.
6976 * @param visMode Element.VISIBILITY or Element.DISPLAY
6977 * @return {Roo.Element} this
6979 setVisibilityMode : function(visMode){
6980 this.visibilityMode = visMode;
6984 * Convenience method for setVisibilityMode(Element.DISPLAY)
6985 * @param {String} display (optional) What to set display to when visible
6986 * @return {Roo.Element} this
6988 enableDisplayMode : function(display){
6989 this.setVisibilityMode(El.DISPLAY);
6990 if(typeof display != "undefined") this.originalDisplay = display;
6995 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6996 * @param {String} selector The simple selector to test
6997 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6998 search as a number or element (defaults to 10 || document.body)
6999 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7000 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7002 findParent : function(simpleSelector, maxDepth, returnEl){
7003 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7004 maxDepth = maxDepth || 50;
7005 if(typeof maxDepth != "number"){
7006 stopEl = Roo.getDom(maxDepth);
7009 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7010 if(dq.is(p, simpleSelector)){
7011 return returnEl ? Roo.get(p) : p;
7021 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7022 * @param {String} selector The simple selector to test
7023 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7024 search as a number or element (defaults to 10 || document.body)
7025 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7026 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7028 findParentNode : function(simpleSelector, maxDepth, returnEl){
7029 var p = Roo.fly(this.dom.parentNode, '_internal');
7030 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7034 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7035 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7036 * @param {String} selector The simple selector to test
7037 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7038 search as a number or element (defaults to 10 || document.body)
7039 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7041 up : function(simpleSelector, maxDepth){
7042 return this.findParentNode(simpleSelector, maxDepth, true);
7048 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7049 * @param {String} selector The simple selector to test
7050 * @return {Boolean} True if this element matches the selector, else false
7052 is : function(simpleSelector){
7053 return Roo.DomQuery.is(this.dom, simpleSelector);
7057 * Perform animation on this element.
7058 * @param {Object} args The YUI animation control args
7059 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7060 * @param {Function} onComplete (optional) Function to call when animation completes
7061 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7062 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7063 * @return {Roo.Element} this
7065 animate : function(args, duration, onComplete, easing, animType){
7066 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7071 * @private Internal animation call
7073 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7074 animType = animType || 'run';
7076 var anim = Roo.lib.Anim[animType](
7078 (opt.duration || defaultDur) || .35,
7079 (opt.easing || defaultEase) || 'easeOut',
7081 Roo.callback(cb, this);
7082 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7090 // private legacy anim prep
7091 preanim : function(a, i){
7092 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7096 * Removes worthless text nodes
7097 * @param {Boolean} forceReclean (optional) By default the element
7098 * keeps track if it has been cleaned already so
7099 * you can call this over and over. However, if you update the element and
7100 * need to force a reclean, you can pass true.
7102 clean : function(forceReclean){
7103 if(this.isCleaned && forceReclean !== true){
7107 var d = this.dom, n = d.firstChild, ni = -1;
7109 var nx = n.nextSibling;
7110 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7117 this.isCleaned = true;
7122 calcOffsetsTo : function(el){
7125 var restorePos = false;
7126 if(el.getStyle('position') == 'static'){
7127 el.position('relative');
7132 while(op && op != d && op.tagName != 'HTML'){
7135 op = op.offsetParent;
7138 el.position('static');
7144 * Scrolls this element into view within the passed container.
7145 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7146 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7147 * @return {Roo.Element} this
7149 scrollIntoView : function(container, hscroll){
7150 var c = Roo.getDom(container) || document.body;
7153 var o = this.calcOffsetsTo(c),
7156 b = t+el.offsetHeight,
7157 r = l+el.offsetWidth;
7159 var ch = c.clientHeight;
7160 var ct = parseInt(c.scrollTop, 10);
7161 var cl = parseInt(c.scrollLeft, 10);
7163 var cr = cl + c.clientWidth;
7171 if(hscroll !== false){
7175 c.scrollLeft = r-c.clientWidth;
7182 scrollChildIntoView : function(child, hscroll){
7183 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7187 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7188 * the new height may not be available immediately.
7189 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7190 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7191 * @param {Function} onComplete (optional) Function to call when animation completes
7192 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7193 * @return {Roo.Element} this
7195 autoHeight : function(animate, duration, onComplete, easing){
7196 var oldHeight = this.getHeight();
7198 this.setHeight(1); // force clipping
7199 setTimeout(function(){
7200 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7202 this.setHeight(height);
7204 if(typeof onComplete == "function"){
7208 this.setHeight(oldHeight); // restore original height
7209 this.setHeight(height, animate, duration, function(){
7211 if(typeof onComplete == "function") onComplete();
7212 }.createDelegate(this), easing);
7214 }.createDelegate(this), 0);
7219 * Returns true if this element is an ancestor of the passed element
7220 * @param {HTMLElement/String} el The element to check
7221 * @return {Boolean} True if this element is an ancestor of el, else false
7223 contains : function(el){
7224 if(!el){return false;}
7225 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7229 * Checks whether the element is currently visible using both visibility and display properties.
7230 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7231 * @return {Boolean} True if the element is currently visible, else false
7233 isVisible : function(deep) {
7234 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7235 if(deep !== true || !vis){
7238 var p = this.dom.parentNode;
7239 while(p && p.tagName.toLowerCase() != "body"){
7240 if(!Roo.fly(p, '_isVisible').isVisible()){
7249 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7250 * @param {String} selector The CSS selector
7251 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7252 * @return {CompositeElement/CompositeElementLite} The composite element
7254 select : function(selector, unique){
7255 return El.select(selector, unique, this.dom);
7259 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7260 * @param {String} selector The CSS selector
7261 * @return {Array} An array of the matched nodes
7263 query : function(selector, unique){
7264 return Roo.DomQuery.select(selector, this.dom);
7268 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7269 * @param {String} selector The CSS selector
7270 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7271 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7273 child : function(selector, returnDom){
7274 var n = Roo.DomQuery.selectNode(selector, this.dom);
7275 return returnDom ? n : Roo.get(n);
7279 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 down : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7291 * @param {String} group The group the DD object is member of
7292 * @param {Object} config The DD config object
7293 * @param {Object} overrides An object containing methods to override/implement on the DD object
7294 * @return {Roo.dd.DD} The DD object
7296 initDD : function(group, config, overrides){
7297 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7298 return Roo.apply(dd, overrides);
7302 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7303 * @param {String} group The group the DDProxy object is member of
7304 * @param {Object} config The DDProxy config object
7305 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7306 * @return {Roo.dd.DDProxy} The DDProxy object
7308 initDDProxy : function(group, config, overrides){
7309 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7310 return Roo.apply(dd, overrides);
7314 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7315 * @param {String} group The group the DDTarget object is member of
7316 * @param {Object} config The DDTarget config object
7317 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7318 * @return {Roo.dd.DDTarget} The DDTarget object
7320 initDDTarget : function(group, config, overrides){
7321 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7322 return Roo.apply(dd, overrides);
7326 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7327 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7328 * @param {Boolean} visible Whether the element is visible
7329 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7330 * @return {Roo.Element} this
7332 setVisible : function(visible, animate){
7334 if(this.visibilityMode == El.DISPLAY){
7335 this.setDisplayed(visible);
7338 this.dom.style.visibility = visible ? "visible" : "hidden";
7341 // closure for composites
7343 var visMode = this.visibilityMode;
7345 this.setOpacity(.01);
7346 this.setVisible(true);
7348 this.anim({opacity: { to: (visible?1:0) }},
7349 this.preanim(arguments, 1),
7350 null, .35, 'easeIn', function(){
7352 if(visMode == El.DISPLAY){
7353 dom.style.display = "none";
7355 dom.style.visibility = "hidden";
7357 Roo.get(dom).setOpacity(1);
7365 * Returns true if display is not "none"
7368 isDisplayed : function() {
7369 return this.getStyle("display") != "none";
7373 * Toggles the element's visibility or display, depending on visibility mode.
7374 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7375 * @return {Roo.Element} this
7377 toggle : function(animate){
7378 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7383 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7384 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7385 * @return {Roo.Element} this
7387 setDisplayed : function(value) {
7388 if(typeof value == "boolean"){
7389 value = value ? this.originalDisplay : "none";
7391 this.setStyle("display", value);
7396 * Tries to focus the element. Any exceptions are caught and ignored.
7397 * @return {Roo.Element} this
7399 focus : function() {
7407 * Tries to blur the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7418 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7419 * @param {String/Array} className The CSS class to add, or an array of classes
7420 * @return {Roo.Element} this
7422 addClass : function(className){
7423 if(className instanceof Array){
7424 for(var i = 0, len = className.length; i < len; i++) {
7425 this.addClass(className[i]);
7428 if(className && !this.hasClass(className)){
7429 this.dom.className = this.dom.className + " " + className;
7436 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7437 * @param {String/Array} className The CSS class to add, or an array of classes
7438 * @return {Roo.Element} this
7440 radioClass : function(className){
7441 var siblings = this.dom.parentNode.childNodes;
7442 for(var i = 0; i < siblings.length; i++) {
7443 var s = siblings[i];
7444 if(s.nodeType == 1){
7445 Roo.get(s).removeClass(className);
7448 this.addClass(className);
7453 * Removes one or more CSS classes from the element.
7454 * @param {String/Array} className The CSS class to remove, or an array of classes
7455 * @return {Roo.Element} this
7457 removeClass : function(className){
7458 if(!className || !this.dom.className){
7461 if(className instanceof Array){
7462 for(var i = 0, len = className.length; i < len; i++) {
7463 this.removeClass(className[i]);
7466 if(this.hasClass(className)){
7467 var re = this.classReCache[className];
7469 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7470 this.classReCache[className] = re;
7472 this.dom.className =
7473 this.dom.className.replace(re, " ");
7483 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7484 * @param {String} className The CSS class to toggle
7485 * @return {Roo.Element} this
7487 toggleClass : function(className){
7488 if(this.hasClass(className)){
7489 this.removeClass(className);
7491 this.addClass(className);
7497 * Checks if the specified CSS class exists on this element's DOM node.
7498 * @param {String} className The CSS class to check for
7499 * @return {Boolean} True if the class exists, else false
7501 hasClass : function(className){
7502 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7506 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7507 * @param {String} oldClassName The CSS class to replace
7508 * @param {String} newClassName The replacement CSS class
7509 * @return {Roo.Element} this
7511 replaceClass : function(oldClassName, newClassName){
7512 this.removeClass(oldClassName);
7513 this.addClass(newClassName);
7518 * Returns an object with properties matching the styles requested.
7519 * For example, el.getStyles('color', 'font-size', 'width') might return
7520 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7521 * @param {String} style1 A style name
7522 * @param {String} style2 A style name
7523 * @param {String} etc.
7524 * @return {Object} The style object
7526 getStyles : function(){
7527 var a = arguments, len = a.length, r = {};
7528 for(var i = 0; i < len; i++){
7529 r[a[i]] = this.getStyle(a[i]);
7535 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7536 * @param {String} property The style property whose value is returned.
7537 * @return {String} The current value of the style property for this element.
7539 getStyle : function(){
7540 return view && view.getComputedStyle ?
7542 var el = this.dom, v, cs, camel;
7543 if(prop == 'float'){
7546 if(el.style && (v = el.style[prop])){
7549 if(cs = view.getComputedStyle(el, "")){
7550 if(!(camel = propCache[prop])){
7551 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7558 var el = this.dom, v, cs, camel;
7559 if(prop == 'opacity'){
7560 if(typeof el.style.filter == 'string'){
7561 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7563 var fv = parseFloat(m[1]);
7565 return fv ? fv / 100 : 0;
7570 }else if(prop == 'float'){
7571 prop = "styleFloat";
7573 if(!(camel = propCache[prop])){
7574 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7576 if(v = el.style[camel]){
7579 if(cs = el.currentStyle){
7587 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7588 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7589 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7590 * @return {Roo.Element} this
7592 setStyle : function(prop, value){
7593 if(typeof prop == "string"){
7595 if (prop == 'float') {
7596 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7601 if(!(camel = propCache[prop])){
7602 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7605 if(camel == 'opacity') {
7606 this.setOpacity(value);
7608 this.dom.style[camel] = value;
7611 for(var style in prop){
7612 if(typeof prop[style] != "function"){
7613 this.setStyle(style, prop[style]);
7621 * More flexible version of {@link #setStyle} for setting style properties.
7622 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7623 * a function which returns such a specification.
7624 * @return {Roo.Element} this
7626 applyStyles : function(style){
7627 Roo.DomHelper.applyStyles(this.dom, style);
7632 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7633 * @return {Number} The X position of the element
7636 return D.getX(this.dom);
7640 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7641 * @return {Number} The Y position of the element
7644 return D.getY(this.dom);
7648 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7649 * @return {Array} The XY position of the element
7652 return D.getXY(this.dom);
7656 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7657 * @param {Number} The X position of the element
7658 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7659 * @return {Roo.Element} this
7661 setX : function(x, animate){
7663 D.setX(this.dom, x);
7665 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7671 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7672 * @param {Number} The Y position of the element
7673 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7674 * @return {Roo.Element} this
7676 setY : function(y, animate){
7678 D.setY(this.dom, y);
7680 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7686 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7687 * @param {String} left The left CSS property value
7688 * @return {Roo.Element} this
7690 setLeft : function(left){
7691 this.setStyle("left", this.addUnits(left));
7696 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7697 * @param {String} top The top CSS property value
7698 * @return {Roo.Element} this
7700 setTop : function(top){
7701 this.setStyle("top", this.addUnits(top));
7706 * Sets the element's CSS right style.
7707 * @param {String} right The right CSS property value
7708 * @return {Roo.Element} this
7710 setRight : function(right){
7711 this.setStyle("right", this.addUnits(right));
7716 * Sets the element's CSS bottom style.
7717 * @param {String} bottom The bottom CSS property value
7718 * @return {Roo.Element} this
7720 setBottom : function(bottom){
7721 this.setStyle("bottom", this.addUnits(bottom));
7726 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7727 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7728 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7729 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7730 * @return {Roo.Element} this
7732 setXY : function(pos, animate){
7734 D.setXY(this.dom, pos);
7736 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7742 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7743 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7744 * @param {Number} x X value for new position (coordinates are page-based)
7745 * @param {Number} y Y value for new position (coordinates are page-based)
7746 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747 * @return {Roo.Element} this
7749 setLocation : function(x, y, animate){
7750 this.setXY([x, y], this.preanim(arguments, 2));
7755 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7756 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7757 * @param {Number} x X value for new position (coordinates are page-based)
7758 * @param {Number} y Y value for new position (coordinates are page-based)
7759 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7760 * @return {Roo.Element} this
7762 moveTo : function(x, y, animate){
7763 this.setXY([x, y], this.preanim(arguments, 2));
7768 * Returns the region of the given element.
7769 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7770 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7772 getRegion : function(){
7773 return D.getRegion(this.dom);
7777 * Returns the offset height of the element
7778 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7779 * @return {Number} The element's height
7781 getHeight : function(contentHeight){
7782 var h = this.dom.offsetHeight || 0;
7783 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7787 * Returns the offset width of the element
7788 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7789 * @return {Number} The element's width
7791 getWidth : function(contentWidth){
7792 var w = this.dom.offsetWidth || 0;
7793 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7797 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7798 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7799 * if a height has not been set using CSS.
7802 getComputedHeight : function(){
7803 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7805 h = parseInt(this.getStyle('height'), 10) || 0;
7806 if(!this.isBorderBox()){
7807 h += this.getFrameWidth('tb');
7814 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7815 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7816 * if a width has not been set using CSS.
7819 getComputedWidth : function(){
7820 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7822 w = parseInt(this.getStyle('width'), 10) || 0;
7823 if(!this.isBorderBox()){
7824 w += this.getFrameWidth('lr');
7831 * Returns the size of the element.
7832 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7833 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7835 getSize : function(contentSize){
7836 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7840 * Returns the width and height of the viewport.
7841 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7843 getViewSize : function(){
7844 var d = this.dom, doc = document, aw = 0, ah = 0;
7845 if(d == doc || d == doc.body){
7846 return {width : D.getViewWidth(), height: D.getViewHeight()};
7849 width : d.clientWidth,
7850 height: d.clientHeight
7856 * Returns the value of the "value" attribute
7857 * @param {Boolean} asNumber true to parse the value as a number
7858 * @return {String/Number}
7860 getValue : function(asNumber){
7861 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7865 adjustWidth : function(width){
7866 if(typeof width == "number"){
7867 if(this.autoBoxAdjust && !this.isBorderBox()){
7868 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7878 adjustHeight : function(height){
7879 if(typeof height == "number"){
7880 if(this.autoBoxAdjust && !this.isBorderBox()){
7881 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7891 * Set the width of the element
7892 * @param {Number} width The new width
7893 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7894 * @return {Roo.Element} this
7896 setWidth : function(width, animate){
7897 width = this.adjustWidth(width);
7899 this.dom.style.width = this.addUnits(width);
7901 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7907 * Set the height of the element
7908 * @param {Number} height The new height
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setHeight : function(height, animate){
7913 height = this.adjustHeight(height);
7915 this.dom.style.height = this.addUnits(height);
7917 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7923 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7924 * @param {Number} width The new width
7925 * @param {Number} height The new height
7926 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7927 * @return {Roo.Element} this
7929 setSize : function(width, height, animate){
7930 if(typeof width == "object"){ // in case of object from getSize()
7931 height = width.height; width = width.width;
7933 width = this.adjustWidth(width); height = this.adjustHeight(height);
7935 this.dom.style.width = this.addUnits(width);
7936 this.dom.style.height = this.addUnits(height);
7938 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7944 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7945 * @param {Number} x X value for new position (coordinates are page-based)
7946 * @param {Number} y Y value for new position (coordinates are page-based)
7947 * @param {Number} width The new width
7948 * @param {Number} height The new height
7949 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7950 * @return {Roo.Element} this
7952 setBounds : function(x, y, width, height, animate){
7954 this.setSize(width, height);
7955 this.setLocation(x, y);
7957 width = this.adjustWidth(width); height = this.adjustHeight(height);
7958 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7959 this.preanim(arguments, 4), 'motion');
7965 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7966 * @param {Roo.lib.Region} region The region to fill
7967 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7968 * @return {Roo.Element} this
7970 setRegion : function(region, animate){
7971 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7976 * Appends an event handler
7978 * @param {String} eventName The type of event to append
7979 * @param {Function} fn The method the event invokes
7980 * @param {Object} scope (optional) The scope (this object) of the fn
7981 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7983 addListener : function(eventName, fn, scope, options){
7985 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7990 * Removes an event handler from this element
7991 * @param {String} eventName the type of event to remove
7992 * @param {Function} fn the method the event invokes
7993 * @return {Roo.Element} this
7995 removeListener : function(eventName, fn){
7996 Roo.EventManager.removeListener(this.dom, eventName, fn);
8001 * Removes all previous added listeners from this element
8002 * @return {Roo.Element} this
8004 removeAllListeners : function(){
8005 E.purgeElement(this.dom);
8009 relayEvent : function(eventName, observable){
8010 this.on(eventName, function(e){
8011 observable.fireEvent(eventName, e);
8016 * Set the opacity of the element
8017 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8018 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8019 * @return {Roo.Element} this
8021 setOpacity : function(opacity, animate){
8023 var s = this.dom.style;
8026 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8027 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8029 s.opacity = opacity;
8032 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8038 * Gets the left X coordinate
8039 * @param {Boolean} local True to get the local css position instead of page coordinate
8042 getLeft : function(local){
8046 return parseInt(this.getStyle("left"), 10) || 0;
8051 * Gets the right X coordinate of the element (element X position + element width)
8052 * @param {Boolean} local True to get the local css position instead of page coordinate
8055 getRight : function(local){
8057 return this.getX() + this.getWidth();
8059 return (this.getLeft(true) + this.getWidth()) || 0;
8064 * Gets the top Y coordinate
8065 * @param {Boolean} local True to get the local css position instead of page coordinate
8068 getTop : function(local) {
8072 return parseInt(this.getStyle("top"), 10) || 0;
8077 * Gets the bottom Y coordinate of the element (element Y position + element height)
8078 * @param {Boolean} local True to get the local css position instead of page coordinate
8081 getBottom : function(local){
8083 return this.getY() + this.getHeight();
8085 return (this.getTop(true) + this.getHeight()) || 0;
8090 * Initializes positioning on this element. If a desired position is not passed, it will make the
8091 * the element positioned relative IF it is not already positioned.
8092 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8093 * @param {Number} zIndex (optional) The zIndex to apply
8094 * @param {Number} x (optional) Set the page X position
8095 * @param {Number} y (optional) Set the page Y position
8097 position : function(pos, zIndex, x, y){
8099 if(this.getStyle('position') == 'static'){
8100 this.setStyle('position', 'relative');
8103 this.setStyle("position", pos);
8106 this.setStyle("z-index", zIndex);
8108 if(x !== undefined && y !== undefined){
8110 }else if(x !== undefined){
8112 }else if(y !== undefined){
8118 * Clear positioning back to the default when the document was loaded
8119 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8120 * @return {Roo.Element} this
8122 clearPositioning : function(value){
8130 "position" : "static"
8136 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8137 * snapshot before performing an update and then restoring the element.
8140 getPositioning : function(){
8141 var l = this.getStyle("left");
8142 var t = this.getStyle("top");
8144 "position" : this.getStyle("position"),
8146 "right" : l ? "" : this.getStyle("right"),
8148 "bottom" : t ? "" : this.getStyle("bottom"),
8149 "z-index" : this.getStyle("z-index")
8154 * Gets the width of the border(s) for the specified side(s)
8155 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8156 * passing lr would get the border (l)eft width + the border (r)ight width.
8157 * @return {Number} The width of the sides passed added together
8159 getBorderWidth : function(side){
8160 return this.addStyles(side, El.borders);
8164 * Gets the width of the padding(s) for the specified side(s)
8165 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8166 * passing lr would get the padding (l)eft + the padding (r)ight.
8167 * @return {Number} The padding of the sides passed added together
8169 getPadding : function(side){
8170 return this.addStyles(side, El.paddings);
8174 * Set positioning with an object returned by getPositioning().
8175 * @param {Object} posCfg
8176 * @return {Roo.Element} this
8178 setPositioning : function(pc){
8179 this.applyStyles(pc);
8180 if(pc.right == "auto"){
8181 this.dom.style.right = "";
8183 if(pc.bottom == "auto"){
8184 this.dom.style.bottom = "";
8190 fixDisplay : function(){
8191 if(this.getStyle("display") == "none"){
8192 this.setStyle("visibility", "hidden");
8193 this.setStyle("display", this.originalDisplay); // first try reverting to default
8194 if(this.getStyle("display") == "none"){ // if that fails, default to block
8195 this.setStyle("display", "block");
8201 * Quick set left and top adding default units
8202 * @param {String} left The left CSS property value
8203 * @param {String} top The top CSS property value
8204 * @return {Roo.Element} this
8206 setLeftTop : function(left, top){
8207 this.dom.style.left = this.addUnits(left);
8208 this.dom.style.top = this.addUnits(top);
8213 * Move this element relative to its current position.
8214 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8215 * @param {Number} distance How far to move the element in pixels
8216 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8217 * @return {Roo.Element} this
8219 move : function(direction, distance, animate){
8220 var xy = this.getXY();
8221 direction = direction.toLowerCase();
8225 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8229 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8234 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8239 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8246 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8247 * @return {Roo.Element} this
8250 if(!this.isClipped){
8251 this.isClipped = true;
8252 this.originalClip = {
8253 "o": this.getStyle("overflow"),
8254 "x": this.getStyle("overflow-x"),
8255 "y": this.getStyle("overflow-y")
8257 this.setStyle("overflow", "hidden");
8258 this.setStyle("overflow-x", "hidden");
8259 this.setStyle("overflow-y", "hidden");
8265 * Return clipping (overflow) to original clipping before clip() was called
8266 * @return {Roo.Element} this
8268 unclip : function(){
8270 this.isClipped = false;
8271 var o = this.originalClip;
8272 if(o.o){this.setStyle("overflow", o.o);}
8273 if(o.x){this.setStyle("overflow-x", o.x);}
8274 if(o.y){this.setStyle("overflow-y", o.y);}
8281 * Gets the x,y coordinates specified by the anchor position on the element.
8282 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8283 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8284 * {width: (target width), height: (target height)} (defaults to the element's current size)
8285 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8286 * @return {Array} [x, y] An array containing the element's x and y coordinates
8288 getAnchorXY : function(anchor, local, s){
8289 //Passing a different size is useful for pre-calculating anchors,
8290 //especially for anchored animations that change the el size.
8292 var w, h, vp = false;
8295 if(d == document.body || d == document){
8297 w = D.getViewWidth(); h = D.getViewHeight();
8299 w = this.getWidth(); h = this.getHeight();
8302 w = s.width; h = s.height;
8304 var x = 0, y = 0, r = Math.round;
8305 switch((anchor || "tl").toLowerCase()){
8347 var sc = this.getScroll();
8348 return [x + sc.left, y + sc.top];
8350 //Add the element's offset xy
8351 var o = this.getXY();
8352 return [x+o[0], y+o[1]];
8356 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8357 * supported position values.
8358 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8359 * @param {String} position The position to align to.
8360 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8361 * @return {Array} [x, y]
8363 getAlignToXY : function(el, p, o){
8367 throw "Element.alignTo with an element that doesn't exist";
8369 var c = false; //constrain to viewport
8370 var p1 = "", p2 = "";
8377 }else if(p.indexOf("-") == -1){
8380 p = p.toLowerCase();
8381 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8383 throw "Element.alignTo with an invalid alignment " + p;
8385 p1 = m[1]; p2 = m[2]; c = !!m[3];
8387 //Subtract the aligned el's internal xy from the target's offset xy
8388 //plus custom offset to get the aligned el's new offset xy
8389 var a1 = this.getAnchorXY(p1, true);
8390 var a2 = el.getAnchorXY(p2, false);
8391 var x = a2[0] - a1[0] + o[0];
8392 var y = a2[1] - a1[1] + o[1];
8394 //constrain the aligned el to viewport if necessary
8395 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8396 // 5px of margin for ie
8397 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8399 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8400 //perpendicular to the vp border, allow the aligned el to slide on that border,
8401 //otherwise swap the aligned el to the opposite border of the target.
8402 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8403 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8404 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8405 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8408 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8409 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8411 if((x+w) > dw + scrollX){
8412 x = swapX ? r.left-w : dw+scrollX-w;
8415 x = swapX ? r.right : scrollX;
8417 if((y+h) > dh + scrollY){
8418 y = swapY ? r.top-h : dh+scrollY-h;
8421 y = swapY ? r.bottom : scrollY;
8428 getConstrainToXY : function(){
8429 var os = {top:0, left:0, bottom:0, right: 0};
8431 return function(el, local, offsets, proposedXY){
8433 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8435 var vw, vh, vx = 0, vy = 0;
8436 if(el.dom == document.body || el.dom == document){
8437 vw = Roo.lib.Dom.getViewWidth();
8438 vh = Roo.lib.Dom.getViewHeight();
8440 vw = el.dom.clientWidth;
8441 vh = el.dom.clientHeight;
8443 var vxy = el.getXY();
8449 var s = el.getScroll();
8451 vx += offsets.left + s.left;
8452 vy += offsets.top + s.top;
8454 vw -= offsets.right;
8455 vh -= offsets.bottom;
8460 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8461 var x = xy[0], y = xy[1];
8462 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8464 // only move it if it needs it
8467 // first validate right/bottom
8476 // then make sure top/left isn't negative
8485 return moved ? [x, y] : false;
8490 adjustForConstraints : function(xy, parent, offsets){
8491 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8495 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8496 * document it aligns it to the viewport.
8497 * The position parameter is optional, and can be specified in any one of the following formats:
8499 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8500 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8501 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8502 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8503 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8504 * element's anchor point, and the second value is used as the target's anchor point.</li>
8506 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8507 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8508 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8509 * that specified in order to enforce the viewport constraints.
8510 * Following are all of the supported anchor positions:
8513 ----- -----------------------------
8514 tl The top left corner (default)
8515 t The center of the top edge
8516 tr The top right corner
8517 l The center of the left edge
8518 c In the center of the element
8519 r The center of the right edge
8520 bl The bottom left corner
8521 b The center of the bottom edge
8522 br The bottom right corner
8526 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8527 el.alignTo("other-el");
8529 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8530 el.alignTo("other-el", "tr?");
8532 // align the bottom right corner of el with the center left edge of other-el
8533 el.alignTo("other-el", "br-l?");
8535 // align the center of el with the bottom left corner of other-el and
8536 // adjust the x position by -6 pixels (and the y position by 0)
8537 el.alignTo("other-el", "c-bl", [-6, 0]);
8539 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8540 * @param {String} position The position to align to.
8541 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8542 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8543 * @return {Roo.Element} this
8545 alignTo : function(element, position, offsets, animate){
8546 var xy = this.getAlignToXY(element, position, offsets);
8547 this.setXY(xy, this.preanim(arguments, 3));
8552 * Anchors an element to another element and realigns it when the window is resized.
8553 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8554 * @param {String} position The position to align to.
8555 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8556 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8557 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8558 * is a number, it is used as the buffer delay (defaults to 50ms).
8559 * @param {Function} callback The function to call after the animation finishes
8560 * @return {Roo.Element} this
8562 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8563 var action = function(){
8564 this.alignTo(el, alignment, offsets, animate);
8565 Roo.callback(callback, this);
8567 Roo.EventManager.onWindowResize(action, this);
8568 var tm = typeof monitorScroll;
8569 if(tm != 'undefined'){
8570 Roo.EventManager.on(window, 'scroll', action, this,
8571 {buffer: tm == 'number' ? monitorScroll : 50});
8573 action.call(this); // align immediately
8577 * Clears any opacity settings from this element. Required in some cases for IE.
8578 * @return {Roo.Element} this
8580 clearOpacity : function(){
8581 if (window.ActiveXObject) {
8582 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8583 this.dom.style.filter = "";
8586 this.dom.style.opacity = "";
8587 this.dom.style["-moz-opacity"] = "";
8588 this.dom.style["-khtml-opacity"] = "";
8594 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8595 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8596 * @return {Roo.Element} this
8598 hide : function(animate){
8599 this.setVisible(false, this.preanim(arguments, 0));
8604 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8605 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8606 * @return {Roo.Element} this
8608 show : function(animate){
8609 this.setVisible(true, this.preanim(arguments, 0));
8614 * @private Test if size has a unit, otherwise appends the default
8616 addUnits : function(size){
8617 return Roo.Element.addUnits(size, this.defaultUnit);
8621 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8622 * @return {Roo.Element} this
8624 beginMeasure : function(){
8626 if(el.offsetWidth || el.offsetHeight){
8627 return this; // offsets work already
8630 var p = this.dom, b = document.body; // start with this element
8631 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8632 var pe = Roo.get(p);
8633 if(pe.getStyle('display') == 'none'){
8634 changed.push({el: p, visibility: pe.getStyle("visibility")});
8635 p.style.visibility = "hidden";
8636 p.style.display = "block";
8640 this._measureChanged = changed;
8646 * Restores displays to before beginMeasure was called
8647 * @return {Roo.Element} this
8649 endMeasure : function(){
8650 var changed = this._measureChanged;
8652 for(var i = 0, len = changed.length; i < len; i++) {
8654 r.el.style.visibility = r.visibility;
8655 r.el.style.display = "none";
8657 this._measureChanged = null;
8663 * Update the innerHTML of this element, optionally searching for and processing scripts
8664 * @param {String} html The new HTML
8665 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8666 * @param {Function} callback For async script loading you can be noticed when the update completes
8667 * @return {Roo.Element} this
8669 update : function(html, loadScripts, callback){
8670 if(typeof html == "undefined"){
8673 if(loadScripts !== true){
8674 this.dom.innerHTML = html;
8675 if(typeof callback == "function"){
8683 html += '<span id="' + id + '"></span>';
8685 E.onAvailable(id, function(){
8686 var hd = document.getElementsByTagName("head")[0];
8687 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8688 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8689 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8692 while(match = re.exec(html)){
8693 var attrs = match[1];
8694 var srcMatch = attrs ? attrs.match(srcRe) : false;
8695 if(srcMatch && srcMatch[2]){
8696 var s = document.createElement("script");
8697 s.src = srcMatch[2];
8698 var typeMatch = attrs.match(typeRe);
8699 if(typeMatch && typeMatch[2]){
8700 s.type = typeMatch[2];
8703 }else if(match[2] && match[2].length > 0){
8704 if(window.execScript) {
8705 window.execScript(match[2]);
8713 window.eval(match[2]);
8717 var el = document.getElementById(id);
8718 if(el){el.parentNode.removeChild(el);}
8719 if(typeof callback == "function"){
8723 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8728 * Direct access to the UpdateManager update() method (takes the same parameters).
8729 * @param {String/Function} url The url for this request or a function to call to get the url
8730 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8731 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8732 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8733 * @return {Roo.Element} this
8736 var um = this.getUpdateManager();
8737 um.update.apply(um, arguments);
8742 * Gets this element's UpdateManager
8743 * @return {Roo.UpdateManager} The UpdateManager
8745 getUpdateManager : function(){
8746 if(!this.updateManager){
8747 this.updateManager = new Roo.UpdateManager(this);
8749 return this.updateManager;
8753 * Disables text selection for this element (normalized across browsers)
8754 * @return {Roo.Element} this
8756 unselectable : function(){
8757 this.dom.unselectable = "on";
8758 this.swallowEvent("selectstart", true);
8759 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8760 this.addClass("x-unselectable");
8765 * Calculates the x, y to center this element on the screen
8766 * @return {Array} The x, y values [x, y]
8768 getCenterXY : function(){
8769 return this.getAlignToXY(document, 'c-c');
8773 * Centers the Element in either the viewport, or another Element.
8774 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8776 center : function(centerIn){
8777 this.alignTo(centerIn || document, 'c-c');
8782 * Tests various css rules/browsers to determine if this element uses a border box
8785 isBorderBox : function(){
8786 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8790 * Return a box {x, y, width, height} that can be used to set another elements
8791 * size/location to match this element.
8792 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8793 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8794 * @return {Object} box An object in the format {x, y, width, height}
8796 getBox : function(contentBox, local){
8801 var left = parseInt(this.getStyle("left"), 10) || 0;
8802 var top = parseInt(this.getStyle("top"), 10) || 0;
8805 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8807 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8809 var l = this.getBorderWidth("l")+this.getPadding("l");
8810 var r = this.getBorderWidth("r")+this.getPadding("r");
8811 var t = this.getBorderWidth("t")+this.getPadding("t");
8812 var b = this.getBorderWidth("b")+this.getPadding("b");
8813 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8815 bx.right = bx.x + bx.width;
8816 bx.bottom = bx.y + bx.height;
8821 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8822 for more information about the sides.
8823 * @param {String} sides
8826 getFrameWidth : function(sides, onlyContentBox){
8827 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8831 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8832 * @param {Object} box The box to fill {x, y, width, height}
8833 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8834 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8835 * @return {Roo.Element} this
8837 setBox : function(box, adjust, animate){
8838 var w = box.width, h = box.height;
8839 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8840 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8841 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8843 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8848 * Forces the browser to repaint this element
8849 * @return {Roo.Element} this
8851 repaint : function(){
8853 this.addClass("x-repaint");
8854 setTimeout(function(){
8855 Roo.get(dom).removeClass("x-repaint");
8861 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8862 * then it returns the calculated width of the sides (see getPadding)
8863 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8864 * @return {Object/Number}
8866 getMargins : function(side){
8869 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8870 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8871 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8872 right: parseInt(this.getStyle("margin-right"), 10) || 0
8875 return this.addStyles(side, El.margins);
8880 addStyles : function(sides, styles){
8882 for(var i = 0, len = sides.length; i < len; i++){
8883 v = this.getStyle(styles[sides.charAt(i)]);
8885 w = parseInt(v, 10);
8893 * Creates a proxy element of this element
8894 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8895 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8896 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8897 * @return {Roo.Element} The new proxy element
8899 createProxy : function(config, renderTo, matchBox){
8901 renderTo = Roo.getDom(renderTo);
8903 renderTo = document.body;
8905 config = typeof config == "object" ?
8906 config : {tag : "div", cls: config};
8907 var proxy = Roo.DomHelper.append(renderTo, config, true);
8909 proxy.setBox(this.getBox());
8915 * Puts a mask over this element to disable user interaction. Requires core.css.
8916 * This method can only be applied to elements which accept child nodes.
8917 * @param {String} msg (optional) A message to display in the mask
8918 * @param {String} msgCls (optional) A css class to apply to the msg element
8919 * @return {Element} The mask element
8921 mask : function(msg, msgCls)
8923 if(this.getStyle("position") == "static"){
8924 this.setStyle("position", "relative");
8927 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8929 this.addClass("x-masked");
8930 this._mask.setDisplayed(true);
8935 while (dom && dom.style) {
8936 if (!isNaN(parseInt(dom.style.zIndex))) {
8937 z = Math.max(z, parseInt(dom.style.zIndex));
8939 dom = dom.parentNode;
8941 // if we are masking the body - then it hides everything..
8942 if (this.dom == document.body) {
8944 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8945 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8948 if(typeof msg == 'string'){
8950 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8952 var mm = this._maskMsg;
8953 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8954 mm.dom.firstChild.innerHTML = msg;
8955 mm.setDisplayed(true);
8957 mm.setStyle('z-index', z + 102);
8959 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8960 this._mask.setHeight(this.getHeight());
8962 this._mask.setStyle('z-index', z + 100);
8968 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8969 * it is cached for reuse.
8971 unmask : function(removeEl){
8973 if(removeEl === true){
8974 this._mask.remove();
8977 this._maskMsg.remove();
8978 delete this._maskMsg;
8981 this._mask.setDisplayed(false);
8983 this._maskMsg.setDisplayed(false);
8987 this.removeClass("x-masked");
8991 * Returns true if this element is masked
8994 isMasked : function(){
8995 return this._mask && this._mask.isVisible();
8999 * Creates an iframe shim for this element to keep selects and other windowed objects from
9001 * @return {Roo.Element} The new shim element
9003 createShim : function(){
9004 var el = document.createElement('iframe');
9005 el.frameBorder = 'no';
9006 el.className = 'roo-shim';
9007 if(Roo.isIE && Roo.isSecure){
9008 el.src = Roo.SSL_SECURE_URL;
9010 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9011 shim.autoBoxAdjust = false;
9016 * Removes this element from the DOM and deletes it from the cache
9018 remove : function(){
9019 if(this.dom.parentNode){
9020 this.dom.parentNode.removeChild(this.dom);
9022 delete El.cache[this.dom.id];
9026 * Sets up event handlers to add and remove a css class when the mouse is over this element
9027 * @param {String} className
9028 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9029 * mouseout events for children elements
9030 * @return {Roo.Element} this
9032 addClassOnOver : function(className, preventFlicker){
9033 this.on("mouseover", function(){
9034 Roo.fly(this, '_internal').addClass(className);
9036 var removeFn = function(e){
9037 if(preventFlicker !== true || !e.within(this, true)){
9038 Roo.fly(this, '_internal').removeClass(className);
9041 this.on("mouseout", removeFn, this.dom);
9046 * Sets up event handlers to add and remove a css class when this element has the focus
9047 * @param {String} className
9048 * @return {Roo.Element} this
9050 addClassOnFocus : function(className){
9051 this.on("focus", function(){
9052 Roo.fly(this, '_internal').addClass(className);
9054 this.on("blur", function(){
9055 Roo.fly(this, '_internal').removeClass(className);
9060 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9061 * @param {String} className
9062 * @return {Roo.Element} this
9064 addClassOnClick : function(className){
9066 this.on("mousedown", function(){
9067 Roo.fly(dom, '_internal').addClass(className);
9068 var d = Roo.get(document);
9069 var fn = function(){
9070 Roo.fly(dom, '_internal').removeClass(className);
9071 d.removeListener("mouseup", fn);
9073 d.on("mouseup", fn);
9079 * Stops the specified event from bubbling and optionally prevents the default action
9080 * @param {String} eventName
9081 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9082 * @return {Roo.Element} this
9084 swallowEvent : function(eventName, preventDefault){
9085 var fn = function(e){
9086 e.stopPropagation();
9091 if(eventName instanceof Array){
9092 for(var i = 0, len = eventName.length; i < len; i++){
9093 this.on(eventName[i], fn);
9097 this.on(eventName, fn);
9104 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9107 * Sizes this element to its parent element's dimensions performing
9108 * neccessary box adjustments.
9109 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9110 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9111 * @return {Roo.Element} this
9113 fitToParent : function(monitorResize, targetParent) {
9114 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9115 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9116 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9119 var p = Roo.get(targetParent || this.dom.parentNode);
9120 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9121 if (monitorResize === true) {
9122 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9123 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9129 * Gets the next sibling, skipping text nodes
9130 * @return {HTMLElement} The next sibling or null
9132 getNextSibling : function(){
9133 var n = this.dom.nextSibling;
9134 while(n && n.nodeType != 1){
9141 * Gets the previous sibling, skipping text nodes
9142 * @return {HTMLElement} The previous sibling or null
9144 getPrevSibling : function(){
9145 var n = this.dom.previousSibling;
9146 while(n && n.nodeType != 1){
9147 n = n.previousSibling;
9154 * Appends the passed element(s) to this element
9155 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9156 * @return {Roo.Element} this
9158 appendChild: function(el){
9165 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9166 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9167 * automatically generated with the specified attributes.
9168 * @param {HTMLElement} insertBefore (optional) a child element of this element
9169 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9170 * @return {Roo.Element} The new child element
9172 createChild: function(config, insertBefore, returnDom){
9173 config = config || {tag:'div'};
9175 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9177 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9181 * Appends this element to the passed element
9182 * @param {String/HTMLElement/Element} el The new parent element
9183 * @return {Roo.Element} this
9185 appendTo: function(el){
9186 el = Roo.getDom(el);
9187 el.appendChild(this.dom);
9192 * Inserts this element before the passed element in the DOM
9193 * @param {String/HTMLElement/Element} el The element to insert before
9194 * @return {Roo.Element} this
9196 insertBefore: function(el){
9197 el = Roo.getDom(el);
9198 el.parentNode.insertBefore(this.dom, el);
9203 * Inserts this element after the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert after
9205 * @return {Roo.Element} this
9207 insertAfter: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el.nextSibling);
9214 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9215 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9216 * @return {Roo.Element} The new child
9218 insertFirst: function(el, returnDom){
9220 if(typeof el == 'object' && !el.nodeType){ // dh config
9221 return this.createChild(el, this.dom.firstChild, returnDom);
9223 el = Roo.getDom(el);
9224 this.dom.insertBefore(el, this.dom.firstChild);
9225 return !returnDom ? Roo.get(el) : el;
9230 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9231 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9232 * @param {String} where (optional) 'before' or 'after' defaults to before
9233 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9234 * @return {Roo.Element} the inserted Element
9236 insertSibling: function(el, where, returnDom){
9237 where = where ? where.toLowerCase() : 'before';
9239 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9241 if(typeof el == 'object' && !el.nodeType){ // dh config
9242 if(where == 'after' && !this.dom.nextSibling){
9243 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9245 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9249 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9250 where == 'before' ? this.dom : this.dom.nextSibling);
9259 * Creates and wraps this element with another element
9260 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9261 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9262 * @return {HTMLElement/Element} The newly created wrapper element
9264 wrap: function(config, returnDom){
9266 config = {tag: "div"};
9268 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9269 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9274 * Replaces the passed element with this element
9275 * @param {String/HTMLElement/Element} el The element to replace
9276 * @return {Roo.Element} this
9278 replace: function(el){
9280 this.insertBefore(el);
9286 * Inserts an html fragment into this element
9287 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9288 * @param {String} html The HTML fragment
9289 * @param {Boolean} returnEl True to return an Roo.Element
9290 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9292 insertHtml : function(where, html, returnEl){
9293 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9294 return returnEl ? Roo.get(el) : el;
9298 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9299 * @param {Object} o The object with the attributes
9300 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9301 * @return {Roo.Element} this
9303 set : function(o, useSet){
9305 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9307 if(attr == "style" || typeof o[attr] == "function") continue;
9309 el.className = o["cls"];
9311 if(useSet) el.setAttribute(attr, o[attr]);
9312 else el[attr] = o[attr];
9316 Roo.DomHelper.applyStyles(el, o.style);
9322 * Convenience method for constructing a KeyMap
9323 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9324 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9325 * @param {Function} fn The function to call
9326 * @param {Object} scope (optional) The scope of the function
9327 * @return {Roo.KeyMap} The KeyMap created
9329 addKeyListener : function(key, fn, scope){
9331 if(typeof key != "object" || key instanceof Array){
9347 return new Roo.KeyMap(this, config);
9351 * Creates a KeyMap for this element
9352 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9353 * @return {Roo.KeyMap} The KeyMap created
9355 addKeyMap : function(config){
9356 return new Roo.KeyMap(this, config);
9360 * Returns true if this element is scrollable.
9363 isScrollable : function(){
9365 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9369 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9370 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9371 * @param {Number} value The new scroll value
9372 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9373 * @return {Element} this
9376 scrollTo : function(side, value, animate){
9377 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9379 this.dom[prop] = value;
9381 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9382 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9388 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9389 * within this element's scrollable range.
9390 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9391 * @param {Number} distance How far to scroll the element in pixels
9392 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9393 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9394 * was scrolled as far as it could go.
9396 scroll : function(direction, distance, animate){
9397 if(!this.isScrollable()){
9401 var l = el.scrollLeft, t = el.scrollTop;
9402 var w = el.scrollWidth, h = el.scrollHeight;
9403 var cw = el.clientWidth, ch = el.clientHeight;
9404 direction = direction.toLowerCase();
9405 var scrolled = false;
9406 var a = this.preanim(arguments, 2);
9411 var v = Math.min(l + distance, w-cw);
9412 this.scrollTo("left", v, a);
9419 var v = Math.max(l - distance, 0);
9420 this.scrollTo("left", v, a);
9428 var v = Math.max(t - distance, 0);
9429 this.scrollTo("top", v, a);
9437 var v = Math.min(t + distance, h-ch);
9438 this.scrollTo("top", v, a);
9447 * Translates the passed page coordinates into left/top css values for this element
9448 * @param {Number/Array} x The page x or an array containing [x, y]
9449 * @param {Number} y The page y
9450 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9452 translatePoints : function(x, y){
9453 if(typeof x == 'object' || x instanceof Array){
9456 var p = this.getStyle('position');
9457 var o = this.getXY();
9459 var l = parseInt(this.getStyle('left'), 10);
9460 var t = parseInt(this.getStyle('top'), 10);
9463 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9466 t = (p == "relative") ? 0 : this.dom.offsetTop;
9469 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9473 * Returns the current scroll position of the element.
9474 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9476 getScroll : function(){
9477 var d = this.dom, doc = document;
9478 if(d == doc || d == doc.body){
9479 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9480 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9481 return {left: l, top: t};
9483 return {left: d.scrollLeft, top: d.scrollTop};
9488 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9489 * are convert to standard 6 digit hex color.
9490 * @param {String} attr The css attribute
9491 * @param {String} defaultValue The default value to use when a valid color isn't found
9492 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9495 getColor : function(attr, defaultValue, prefix){
9496 var v = this.getStyle(attr);
9497 if(!v || v == "transparent" || v == "inherit") {
9498 return defaultValue;
9500 var color = typeof prefix == "undefined" ? "#" : prefix;
9501 if(v.substr(0, 4) == "rgb("){
9502 var rvs = v.slice(4, v.length -1).split(",");
9503 for(var i = 0; i < 3; i++){
9504 var h = parseInt(rvs[i]).toString(16);
9511 if(v.substr(0, 1) == "#"){
9513 for(var i = 1; i < 4; i++){
9514 var c = v.charAt(i);
9517 }else if(v.length == 7){
9518 color += v.substr(1);
9522 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9526 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9527 * gradient background, rounded corners and a 4-way shadow.
9528 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9529 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9530 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9531 * @return {Roo.Element} this
9533 boxWrap : function(cls){
9534 cls = cls || 'x-box';
9535 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9536 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9541 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9542 * @param {String} namespace The namespace in which to look for the attribute
9543 * @param {String} name The attribute name
9544 * @return {String} The attribute value
9546 getAttributeNS : Roo.isIE ? function(ns, name){
9548 var type = typeof d[ns+":"+name];
9549 if(type != 'undefined' && type != 'unknown'){
9550 return d[ns+":"+name];
9553 } : function(ns, name){
9555 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9559 var ep = El.prototype;
9562 * Appends an event handler (Shorthand for addListener)
9563 * @param {String} eventName The type of event to append
9564 * @param {Function} fn The method the event invokes
9565 * @param {Object} scope (optional) The scope (this object) of the fn
9566 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9569 ep.on = ep.addListener;
9571 ep.mon = ep.addListener;
9574 * Removes an event handler from this element (shorthand for removeListener)
9575 * @param {String} eventName the type of event to remove
9576 * @param {Function} fn the method the event invokes
9577 * @return {Roo.Element} this
9580 ep.un = ep.removeListener;
9583 * true to automatically adjust width and height settings for box-model issues (default to true)
9585 ep.autoBoxAdjust = true;
9588 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9591 El.addUnits = function(v, defaultUnit){
9592 if(v === "" || v == "auto"){
9595 if(v === undefined){
9598 if(typeof v == "number" || !El.unitPattern.test(v)){
9599 return v + (defaultUnit || 'px');
9604 // special markup used throughout Roo when box wrapping elements
9605 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9607 * Visibility mode constant - Use visibility to hide element
9613 * Visibility mode constant - Use display to hide element
9619 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9620 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9621 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9633 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9634 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9635 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9636 * @return {Element} The Element object
9639 El.get = function(el){
9641 if(!el){ return null; }
9642 if(typeof el == "string"){ // element id
9643 if(!(elm = document.getElementById(el))){
9646 if(ex = El.cache[el]){
9649 ex = El.cache[el] = new El(elm);
9652 }else if(el.tagName){ // dom element
9656 if(ex = El.cache[id]){
9659 ex = El.cache[id] = new El(el);
9662 }else if(el instanceof El){
9664 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9665 // catch case where it hasn't been appended
9666 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9669 }else if(el.isComposite){
9671 }else if(el instanceof Array){
9672 return El.select(el);
9673 }else if(el == document){
9674 // create a bogus element object representing the document object
9676 var f = function(){};
9677 f.prototype = El.prototype;
9679 docEl.dom = document;
9687 El.uncache = function(el){
9688 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9690 delete El.cache[a[i].id || a[i]];
9696 // Garbage collection - uncache elements/purge listeners on orphaned elements
9697 // so we don't hold a reference and cause the browser to retain them
9698 El.garbageCollect = function(){
9699 if(!Roo.enableGarbageCollector){
9700 clearInterval(El.collectorThread);
9703 for(var eid in El.cache){
9704 var el = El.cache[eid], d = el.dom;
9705 // -------------------------------------------------------
9706 // Determining what is garbage:
9707 // -------------------------------------------------------
9709 // dom node is null, definitely garbage
9710 // -------------------------------------------------------
9712 // no parentNode == direct orphan, definitely garbage
9713 // -------------------------------------------------------
9714 // !d.offsetParent && !document.getElementById(eid)
9715 // display none elements have no offsetParent so we will
9716 // also try to look it up by it's id. However, check
9717 // offsetParent first so we don't do unneeded lookups.
9718 // This enables collection of elements that are not orphans
9719 // directly, but somewhere up the line they have an orphan
9721 // -------------------------------------------------------
9722 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9723 delete El.cache[eid];
9724 if(d && Roo.enableListenerCollection){
9730 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9734 El.Flyweight = function(dom){
9737 El.Flyweight.prototype = El.prototype;
9739 El._flyweights = {};
9741 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9742 * the dom node can be overwritten by other code.
9743 * @param {String/HTMLElement} el The dom node or id
9744 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9745 * prevent conflicts (e.g. internally Roo uses "_internal")
9747 * @return {Element} The shared Element object
9749 El.fly = function(el, named){
9750 named = named || '_global';
9751 el = Roo.getDom(el);
9755 if(!El._flyweights[named]){
9756 El._flyweights[named] = new El.Flyweight();
9758 El._flyweights[named].dom = el;
9759 return El._flyweights[named];
9763 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9764 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9765 * Shorthand of {@link Roo.Element#get}
9766 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9767 * @return {Element} The Element object
9773 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9774 * the dom node can be overwritten by other code.
9775 * Shorthand of {@link Roo.Element#fly}
9776 * @param {String/HTMLElement} el The dom node or id
9777 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9778 * prevent conflicts (e.g. internally Roo uses "_internal")
9780 * @return {Element} The shared Element object
9786 // speedy lookup for elements never to box adjust
9787 var noBoxAdjust = Roo.isStrict ? {
9790 input:1, select:1, textarea:1
9792 if(Roo.isIE || Roo.isGecko){
9793 noBoxAdjust['button'] = 1;
9797 Roo.EventManager.on(window, 'unload', function(){
9799 delete El._flyweights;
9807 Roo.Element.selectorFunction = Roo.DomQuery.select;
9810 Roo.Element.select = function(selector, unique, root){
9812 if(typeof selector == "string"){
9813 els = Roo.Element.selectorFunction(selector, root);
9814 }else if(selector.length !== undefined){
9817 throw "Invalid selector";
9819 if(unique === true){
9820 return new Roo.CompositeElement(els);
9822 return new Roo.CompositeElementLite(els);
9826 * Selects elements based on the passed CSS selector to enable working on them as 1.
9827 * @param {String/Array} selector The CSS selector or an array of elements
9828 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9829 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9830 * @return {CompositeElementLite/CompositeElement}
9834 Roo.select = Roo.Element.select;
9851 * Ext JS Library 1.1.1
9852 * Copyright(c) 2006-2007, Ext JS, LLC.
9854 * Originally Released Under LGPL - original licence link has changed is not relivant.
9857 * <script type="text/javascript">
9862 //Notifies Element that fx methods are available
9863 Roo.enableFx = true;
9867 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9868 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9869 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9870 * Element effects to work.</p><br/>
9872 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9873 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9874 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9875 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9876 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9877 * expected results and should be done with care.</p><br/>
9879 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9880 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9883 ----- -----------------------------
9884 tl The top left corner
9885 t The center of the top edge
9886 tr The top right corner
9887 l The center of the left edge
9888 r The center of the right edge
9889 bl The bottom left corner
9890 b The center of the bottom edge
9891 br The bottom right corner
9893 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9894 * below are common options that can be passed to any Fx method.</b>
9895 * @cfg {Function} callback A function called when the effect is finished
9896 * @cfg {Object} scope The scope of the effect function
9897 * @cfg {String} easing A valid Easing value for the effect
9898 * @cfg {String} afterCls A css class to apply after the effect
9899 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9900 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9901 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9902 * effects that end with the element being visually hidden, ignored otherwise)
9903 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9904 * a function which returns such a specification that will be applied to the Element after the effect finishes
9905 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9906 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9907 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9911 * Slides the element into view. An anchor point can be optionally passed to set the point of
9912 * origin for the slide effect. This function automatically handles wrapping the element with
9913 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9916 // default: slide the element in from the top
9919 // custom: slide the element in from the right with a 2-second duration
9920 el.slideIn('r', { duration: 2 });
9922 // common config options shown with default values
9928 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9929 * @param {Object} options (optional) Object literal with any of the Fx config options
9930 * @return {Roo.Element} The Element
9932 slideIn : function(anchor, o){
9933 var el = this.getFxEl();
9936 el.queueFx(o, function(){
9938 anchor = anchor || "t";
9940 // fix display to visibility
9943 // restore values after effect
9944 var r = this.getFxRestore();
9945 var b = this.getBox();
9946 // fixed size for slide
9950 var wrap = this.fxWrap(r.pos, o, "hidden");
9952 var st = this.dom.style;
9953 st.visibility = "visible";
9954 st.position = "absolute";
9956 // clear out temp styles after slide and unwrap
9957 var after = function(){
9958 el.fxUnwrap(wrap, r.pos, o);
9960 st.height = r.height;
9963 // time to calc the positions
9964 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9966 switch(anchor.toLowerCase()){
9968 wrap.setSize(b.width, 0);
9969 st.left = st.bottom = "0";
9973 wrap.setSize(0, b.height);
9974 st.right = st.top = "0";
9978 wrap.setSize(0, b.height);
9980 st.left = st.top = "0";
9981 a = {width: bw, points: pt};
9984 wrap.setSize(b.width, 0);
9985 wrap.setY(b.bottom);
9986 st.left = st.top = "0";
9987 a = {height: bh, points: pt};
9991 st.right = st.bottom = "0";
9992 a = {width: bw, height: bh};
9996 wrap.setY(b.y+b.height);
9997 st.right = st.top = "0";
9998 a = {width: bw, height: bh, points: pt};
10001 wrap.setSize(0, 0);
10002 wrap.setXY([b.right, b.bottom]);
10003 st.left = st.top = "0";
10004 a = {width: bw, height: bh, points: pt};
10007 wrap.setSize(0, 0);
10008 wrap.setX(b.x+b.width);
10009 st.left = st.bottom = "0";
10010 a = {width: bw, height: bh, points: pt};
10013 this.dom.style.visibility = "visible";
10016 arguments.callee.anim = wrap.fxanim(a,
10026 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10027 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10028 * 'hidden') but block elements will still take up space in the document. The element must be removed
10029 * from the DOM using the 'remove' config option if desired. This function automatically handles
10030 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10033 // default: slide the element out to the top
10036 // custom: slide the element out to the right with a 2-second duration
10037 el.slideOut('r', { duration: 2 });
10039 // common config options shown with default values
10047 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10048 * @param {Object} options (optional) Object literal with any of the Fx config options
10049 * @return {Roo.Element} The Element
10051 slideOut : function(anchor, o){
10052 var el = this.getFxEl();
10055 el.queueFx(o, function(){
10057 anchor = anchor || "t";
10059 // restore values after effect
10060 var r = this.getFxRestore();
10062 var b = this.getBox();
10063 // fixed size for slide
10067 var wrap = this.fxWrap(r.pos, o, "visible");
10069 var st = this.dom.style;
10070 st.visibility = "visible";
10071 st.position = "absolute";
10075 var after = function(){
10077 el.setDisplayed(false);
10082 el.fxUnwrap(wrap, r.pos, o);
10084 st.width = r.width;
10085 st.height = r.height;
10090 var a, zero = {to: 0};
10091 switch(anchor.toLowerCase()){
10093 st.left = st.bottom = "0";
10094 a = {height: zero};
10097 st.right = st.top = "0";
10101 st.left = st.top = "0";
10102 a = {width: zero, points: {to:[b.right, b.y]}};
10105 st.left = st.top = "0";
10106 a = {height: zero, points: {to:[b.x, b.bottom]}};
10109 st.right = st.bottom = "0";
10110 a = {width: zero, height: zero};
10113 st.right = st.top = "0";
10114 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10117 st.left = st.top = "0";
10118 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10121 st.left = st.bottom = "0";
10122 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10126 arguments.callee.anim = wrap.fxanim(a,
10136 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10137 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10138 * The element must be removed from the DOM using the 'remove' config option if desired.
10144 // common config options shown with default values
10152 * @param {Object} options (optional) Object literal with any of the Fx config options
10153 * @return {Roo.Element} The Element
10155 puff : function(o){
10156 var el = this.getFxEl();
10159 el.queueFx(o, function(){
10160 this.clearOpacity();
10163 // restore values after effect
10164 var r = this.getFxRestore();
10165 var st = this.dom.style;
10167 var after = function(){
10169 el.setDisplayed(false);
10176 el.setPositioning(r.pos);
10177 st.width = r.width;
10178 st.height = r.height;
10183 var width = this.getWidth();
10184 var height = this.getHeight();
10186 arguments.callee.anim = this.fxanim({
10187 width : {to: this.adjustWidth(width * 2)},
10188 height : {to: this.adjustHeight(height * 2)},
10189 points : {by: [-(width * .5), -(height * .5)]},
10191 fontSize: {to:200, unit: "%"}
10202 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10203 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10204 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10210 // all config options shown with default values
10218 * @param {Object} options (optional) Object literal with any of the Fx config options
10219 * @return {Roo.Element} The Element
10221 switchOff : function(o){
10222 var el = this.getFxEl();
10225 el.queueFx(o, function(){
10226 this.clearOpacity();
10229 // restore values after effect
10230 var r = this.getFxRestore();
10231 var st = this.dom.style;
10233 var after = function(){
10235 el.setDisplayed(false);
10241 el.setPositioning(r.pos);
10242 st.width = r.width;
10243 st.height = r.height;
10248 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10249 this.clearOpacity();
10253 points:{by:[0, this.getHeight() * .5]}
10254 }, o, 'motion', 0.3, 'easeIn', after);
10255 }).defer(100, this);
10262 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10263 * changed using the "attr" config option) and then fading back to the original color. If no original
10264 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10267 // default: highlight background to yellow
10270 // custom: highlight foreground text to blue for 2 seconds
10271 el.highlight("0000ff", { attr: 'color', duration: 2 });
10273 // common config options shown with default values
10274 el.highlight("ffff9c", {
10275 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10276 endColor: (current color) or "ffffff",
10281 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10282 * @param {Object} options (optional) Object literal with any of the Fx config options
10283 * @return {Roo.Element} The Element
10285 highlight : function(color, o){
10286 var el = this.getFxEl();
10289 el.queueFx(o, function(){
10290 color = color || "ffff9c";
10291 attr = o.attr || "backgroundColor";
10293 this.clearOpacity();
10296 var origColor = this.getColor(attr);
10297 var restoreColor = this.dom.style[attr];
10298 endColor = (o.endColor || origColor) || "ffffff";
10300 var after = function(){
10301 el.dom.style[attr] = restoreColor;
10306 a[attr] = {from: color, to: endColor};
10307 arguments.callee.anim = this.fxanim(a,
10317 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10320 // default: a single light blue ripple
10323 // custom: 3 red ripples lasting 3 seconds total
10324 el.frame("ff0000", 3, { duration: 3 });
10326 // common config options shown with default values
10327 el.frame("C3DAF9", 1, {
10328 duration: 1 //duration of entire animation (not each individual ripple)
10329 // Note: Easing is not configurable and will be ignored if included
10332 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10333 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10334 * @param {Object} options (optional) Object literal with any of the Fx config options
10335 * @return {Roo.Element} The Element
10337 frame : function(color, count, o){
10338 var el = this.getFxEl();
10341 el.queueFx(o, function(){
10342 color = color || "#C3DAF9";
10343 if(color.length == 6){
10344 color = "#" + color;
10346 count = count || 1;
10347 duration = o.duration || 1;
10350 var b = this.getBox();
10351 var animFn = function(){
10352 var proxy = this.createProxy({
10355 visbility:"hidden",
10356 position:"absolute",
10357 "z-index":"35000", // yee haw
10358 border:"0px solid " + color
10361 var scale = Roo.isBorderBox ? 2 : 1;
10363 top:{from:b.y, to:b.y - 20},
10364 left:{from:b.x, to:b.x - 20},
10365 borderWidth:{from:0, to:10},
10366 opacity:{from:1, to:0},
10367 height:{from:b.height, to:(b.height + (20*scale))},
10368 width:{from:b.width, to:(b.width + (20*scale))}
10369 }, duration, function(){
10373 animFn.defer((duration/2)*1000, this);
10384 * Creates a pause before any subsequent queued effects begin. If there are
10385 * no effects queued after the pause it will have no effect.
10390 * @param {Number} seconds The length of time to pause (in seconds)
10391 * @return {Roo.Element} The Element
10393 pause : function(seconds){
10394 var el = this.getFxEl();
10397 el.queueFx(o, function(){
10398 setTimeout(function(){
10400 }, seconds * 1000);
10406 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10407 * using the "endOpacity" config option.
10410 // default: fade in from opacity 0 to 100%
10413 // custom: fade in from opacity 0 to 75% over 2 seconds
10414 el.fadeIn({ endOpacity: .75, duration: 2});
10416 // common config options shown with default values
10418 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10423 * @param {Object} options (optional) Object literal with any of the Fx config options
10424 * @return {Roo.Element} The Element
10426 fadeIn : function(o){
10427 var el = this.getFxEl();
10429 el.queueFx(o, function(){
10430 this.setOpacity(0);
10432 this.dom.style.visibility = 'visible';
10433 var to = o.endOpacity || 1;
10434 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10435 o, null, .5, "easeOut", function(){
10437 this.clearOpacity();
10446 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10447 * using the "endOpacity" config option.
10450 // default: fade out from the element's current opacity to 0
10453 // custom: fade out from the element's current opacity to 25% over 2 seconds
10454 el.fadeOut({ endOpacity: .25, duration: 2});
10456 // common config options shown with default values
10458 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10465 * @param {Object} options (optional) Object literal with any of the Fx config options
10466 * @return {Roo.Element} The Element
10468 fadeOut : function(o){
10469 var el = this.getFxEl();
10471 el.queueFx(o, function(){
10472 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10473 o, null, .5, "easeOut", function(){
10474 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10475 this.dom.style.display = "none";
10477 this.dom.style.visibility = "hidden";
10479 this.clearOpacity();
10487 * Animates the transition of an element's dimensions from a starting height/width
10488 * to an ending height/width.
10491 // change height and width to 100x100 pixels
10492 el.scale(100, 100);
10494 // common config options shown with default values. The height and width will default to
10495 // the element's existing values if passed as null.
10498 [element's height], {
10503 * @param {Number} width The new width (pass undefined to keep the original width)
10504 * @param {Number} height The new height (pass undefined to keep the original height)
10505 * @param {Object} options (optional) Object literal with any of the Fx config options
10506 * @return {Roo.Element} The Element
10508 scale : function(w, h, o){
10509 this.shift(Roo.apply({}, o, {
10517 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10518 * Any of these properties not specified in the config object will not be changed. This effect
10519 * requires that at least one new dimension, position or opacity setting must be passed in on
10520 * the config object in order for the function to have any effect.
10523 // slide the element horizontally to x position 200 while changing the height and opacity
10524 el.shift({ x: 200, height: 50, opacity: .8 });
10526 // common config options shown with default values.
10528 width: [element's width],
10529 height: [element's height],
10530 x: [element's x position],
10531 y: [element's y position],
10532 opacity: [element's opacity],
10537 * @param {Object} options Object literal with any of the Fx config options
10538 * @return {Roo.Element} The Element
10540 shift : function(o){
10541 var el = this.getFxEl();
10543 el.queueFx(o, function(){
10544 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10545 if(w !== undefined){
10546 a.width = {to: this.adjustWidth(w)};
10548 if(h !== undefined){
10549 a.height = {to: this.adjustHeight(h)};
10551 if(x !== undefined || y !== undefined){
10553 x !== undefined ? x : this.getX(),
10554 y !== undefined ? y : this.getY()
10557 if(op !== undefined){
10558 a.opacity = {to: op};
10560 if(o.xy !== undefined){
10561 a.points = {to: o.xy};
10563 arguments.callee.anim = this.fxanim(a,
10564 o, 'motion', .35, "easeOut", function(){
10572 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10573 * ending point of the effect.
10576 // default: slide the element downward while fading out
10579 // custom: slide the element out to the right with a 2-second duration
10580 el.ghost('r', { duration: 2 });
10582 // common config options shown with default values
10590 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10591 * @param {Object} options (optional) Object literal with any of the Fx config options
10592 * @return {Roo.Element} The Element
10594 ghost : function(anchor, o){
10595 var el = this.getFxEl();
10598 el.queueFx(o, function(){
10599 anchor = anchor || "b";
10601 // restore values after effect
10602 var r = this.getFxRestore();
10603 var w = this.getWidth(),
10604 h = this.getHeight();
10606 var st = this.dom.style;
10608 var after = function(){
10610 el.setDisplayed(false);
10616 el.setPositioning(r.pos);
10617 st.width = r.width;
10618 st.height = r.height;
10623 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10624 switch(anchor.toLowerCase()){
10651 arguments.callee.anim = this.fxanim(a,
10661 * Ensures that all effects queued after syncFx is called on the element are
10662 * run concurrently. This is the opposite of {@link #sequenceFx}.
10663 * @return {Roo.Element} The Element
10665 syncFx : function(){
10666 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10675 * Ensures that all effects queued after sequenceFx is called on the element are
10676 * run in sequence. This is the opposite of {@link #syncFx}.
10677 * @return {Roo.Element} The Element
10679 sequenceFx : function(){
10680 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10682 concurrent : false,
10689 nextFx : function(){
10690 var ef = this.fxQueue[0];
10697 * Returns true if the element has any effects actively running or queued, else returns false.
10698 * @return {Boolean} True if element has active effects, else false
10700 hasActiveFx : function(){
10701 return this.fxQueue && this.fxQueue[0];
10705 * Stops any running effects and clears the element's internal effects queue if it contains
10706 * any additional effects that haven't started yet.
10707 * @return {Roo.Element} The Element
10709 stopFx : function(){
10710 if(this.hasActiveFx()){
10711 var cur = this.fxQueue[0];
10712 if(cur && cur.anim && cur.anim.isAnimated()){
10713 this.fxQueue = [cur]; // clear out others
10714 cur.anim.stop(true);
10721 beforeFx : function(o){
10722 if(this.hasActiveFx() && !o.concurrent){
10733 * Returns true if the element is currently blocking so that no other effect can be queued
10734 * until this effect is finished, else returns false if blocking is not set. This is commonly
10735 * used to ensure that an effect initiated by a user action runs to completion prior to the
10736 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10737 * @return {Boolean} True if blocking, else false
10739 hasFxBlock : function(){
10740 var q = this.fxQueue;
10741 return q && q[0] && q[0].block;
10745 queueFx : function(o, fn){
10749 if(!this.hasFxBlock()){
10750 Roo.applyIf(o, this.fxDefaults);
10752 var run = this.beforeFx(o);
10753 fn.block = o.block;
10754 this.fxQueue.push(fn);
10766 fxWrap : function(pos, o, vis){
10768 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10771 wrapXY = this.getXY();
10773 var div = document.createElement("div");
10774 div.style.visibility = vis;
10775 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10776 wrap.setPositioning(pos);
10777 if(wrap.getStyle("position") == "static"){
10778 wrap.position("relative");
10780 this.clearPositioning('auto');
10782 wrap.dom.appendChild(this.dom);
10784 wrap.setXY(wrapXY);
10791 fxUnwrap : function(wrap, pos, o){
10792 this.clearPositioning();
10793 this.setPositioning(pos);
10795 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10801 getFxRestore : function(){
10802 var st = this.dom.style;
10803 return {pos: this.getPositioning(), width: st.width, height : st.height};
10807 afterFx : function(o){
10809 this.applyStyles(o.afterStyle);
10812 this.addClass(o.afterCls);
10814 if(o.remove === true){
10817 Roo.callback(o.callback, o.scope, [this]);
10819 this.fxQueue.shift();
10825 getFxEl : function(){ // support for composite element fx
10826 return Roo.get(this.dom);
10830 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10831 animType = animType || 'run';
10833 var anim = Roo.lib.Anim[animType](
10835 (opt.duration || defaultDur) || .35,
10836 (opt.easing || defaultEase) || 'easeOut',
10838 Roo.callback(cb, this);
10847 // backwords compat
10848 Roo.Fx.resize = Roo.Fx.scale;
10850 //When included, Roo.Fx is automatically applied to Element so that all basic
10851 //effects are available directly via the Element API
10852 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10854 * Ext JS Library 1.1.1
10855 * Copyright(c) 2006-2007, Ext JS, LLC.
10857 * Originally Released Under LGPL - original licence link has changed is not relivant.
10860 * <script type="text/javascript">
10865 * @class Roo.CompositeElement
10866 * Standard composite class. Creates a Roo.Element for every element in the collection.
10868 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10869 * actions will be performed on all the elements in this collection.</b>
10871 * All methods return <i>this</i> and can be chained.
10873 var els = Roo.select("#some-el div.some-class", true);
10874 // or select directly from an existing element
10875 var el = Roo.get('some-el');
10876 el.select('div.some-class', true);
10878 els.setWidth(100); // all elements become 100 width
10879 els.hide(true); // all elements fade out and hide
10881 els.setWidth(100).hide(true);
10884 Roo.CompositeElement = function(els){
10885 this.elements = [];
10886 this.addElements(els);
10888 Roo.CompositeElement.prototype = {
10890 addElements : function(els){
10891 if(!els) return this;
10892 if(typeof els == "string"){
10893 els = Roo.Element.selectorFunction(els);
10895 var yels = this.elements;
10896 var index = yels.length-1;
10897 for(var i = 0, len = els.length; i < len; i++) {
10898 yels[++index] = Roo.get(els[i]);
10904 * Clears this composite and adds the elements returned by the passed selector.
10905 * @param {String/Array} els A string CSS selector, an array of elements or an element
10906 * @return {CompositeElement} this
10908 fill : function(els){
10909 this.elements = [];
10915 * Filters this composite to only elements that match the passed selector.
10916 * @param {String} selector A string CSS selector
10917 * @return {CompositeElement} this
10919 filter : function(selector){
10921 this.each(function(el){
10922 if(el.is(selector)){
10923 els[els.length] = el.dom;
10930 invoke : function(fn, args){
10931 var els = this.elements;
10932 for(var i = 0, len = els.length; i < len; i++) {
10933 Roo.Element.prototype[fn].apply(els[i], args);
10938 * Adds elements to this composite.
10939 * @param {String/Array} els A string CSS selector, an array of elements or an element
10940 * @return {CompositeElement} this
10942 add : function(els){
10943 if(typeof els == "string"){
10944 this.addElements(Roo.Element.selectorFunction(els));
10945 }else if(els.length !== undefined){
10946 this.addElements(els);
10948 this.addElements([els]);
10953 * Calls the passed function passing (el, this, index) for each element in this composite.
10954 * @param {Function} fn The function to call
10955 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10956 * @return {CompositeElement} this
10958 each : function(fn, scope){
10959 var els = this.elements;
10960 for(var i = 0, len = els.length; i < len; i++){
10961 if(fn.call(scope || els[i], els[i], this, i) === false) {
10969 * Returns the Element object at the specified index
10970 * @param {Number} index
10971 * @return {Roo.Element}
10973 item : function(index){
10974 return this.elements[index] || null;
10978 * Returns the first Element
10979 * @return {Roo.Element}
10981 first : function(){
10982 return this.item(0);
10986 * Returns the last Element
10987 * @return {Roo.Element}
10990 return this.item(this.elements.length-1);
10994 * Returns the number of elements in this composite
10997 getCount : function(){
10998 return this.elements.length;
11002 * Returns true if this composite contains the passed element
11005 contains : function(el){
11006 return this.indexOf(el) !== -1;
11010 * Returns true if this composite contains the passed element
11013 indexOf : function(el){
11014 return this.elements.indexOf(Roo.get(el));
11019 * Removes the specified element(s).
11020 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11021 * or an array of any of those.
11022 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11023 * @return {CompositeElement} this
11025 removeElement : function(el, removeDom){
11026 if(el instanceof Array){
11027 for(var i = 0, len = el.length; i < len; i++){
11028 this.removeElement(el[i]);
11032 var index = typeof el == 'number' ? el : this.indexOf(el);
11035 var d = this.elements[index];
11039 d.parentNode.removeChild(d);
11042 this.elements.splice(index, 1);
11048 * Replaces the specified element with the passed element.
11049 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11051 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11052 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11053 * @return {CompositeElement} this
11055 replaceElement : function(el, replacement, domReplace){
11056 var index = typeof el == 'number' ? el : this.indexOf(el);
11059 this.elements[index].replaceWith(replacement);
11061 this.elements.splice(index, 1, Roo.get(replacement))
11068 * Removes all elements.
11070 clear : function(){
11071 this.elements = [];
11075 Roo.CompositeElement.createCall = function(proto, fnName){
11076 if(!proto[fnName]){
11077 proto[fnName] = function(){
11078 return this.invoke(fnName, arguments);
11082 for(var fnName in Roo.Element.prototype){
11083 if(typeof Roo.Element.prototype[fnName] == "function"){
11084 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11090 * Ext JS Library 1.1.1
11091 * Copyright(c) 2006-2007, Ext JS, LLC.
11093 * Originally Released Under LGPL - original licence link has changed is not relivant.
11096 * <script type="text/javascript">
11100 * @class Roo.CompositeElementLite
11101 * @extends Roo.CompositeElement
11102 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11104 var els = Roo.select("#some-el div.some-class");
11105 // or select directly from an existing element
11106 var el = Roo.get('some-el');
11107 el.select('div.some-class');
11109 els.setWidth(100); // all elements become 100 width
11110 els.hide(true); // all elements fade out and hide
11112 els.setWidth(100).hide(true);
11113 </code></pre><br><br>
11114 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11115 * actions will be performed on all the elements in this collection.</b>
11117 Roo.CompositeElementLite = function(els){
11118 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11119 this.el = new Roo.Element.Flyweight();
11121 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11122 addElements : function(els){
11124 if(els instanceof Array){
11125 this.elements = this.elements.concat(els);
11127 var yels = this.elements;
11128 var index = yels.length-1;
11129 for(var i = 0, len = els.length; i < len; i++) {
11130 yels[++index] = els[i];
11136 invoke : function(fn, args){
11137 var els = this.elements;
11139 for(var i = 0, len = els.length; i < len; i++) {
11141 Roo.Element.prototype[fn].apply(el, args);
11146 * Returns a flyweight Element of the dom element object at the specified index
11147 * @param {Number} index
11148 * @return {Roo.Element}
11150 item : function(index){
11151 if(!this.elements[index]){
11154 this.el.dom = this.elements[index];
11158 // fixes scope with flyweight
11159 addListener : function(eventName, handler, scope, opt){
11160 var els = this.elements;
11161 for(var i = 0, len = els.length; i < len; i++) {
11162 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11168 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11169 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11170 * a reference to the dom node, use el.dom.</b>
11171 * @param {Function} fn The function to call
11172 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11173 * @return {CompositeElement} this
11175 each : function(fn, scope){
11176 var els = this.elements;
11178 for(var i = 0, len = els.length; i < len; i++){
11180 if(fn.call(scope || el, el, this, i) === false){
11187 indexOf : function(el){
11188 return this.elements.indexOf(Roo.getDom(el));
11191 replaceElement : function(el, replacement, domReplace){
11192 var index = typeof el == 'number' ? el : this.indexOf(el);
11194 replacement = Roo.getDom(replacement);
11196 var d = this.elements[index];
11197 d.parentNode.insertBefore(replacement, d);
11198 d.parentNode.removeChild(d);
11200 this.elements.splice(index, 1, replacement);
11205 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11209 * Ext JS Library 1.1.1
11210 * Copyright(c) 2006-2007, Ext JS, LLC.
11212 * Originally Released Under LGPL - original licence link has changed is not relivant.
11215 * <script type="text/javascript">
11221 * @class Roo.data.Connection
11222 * @extends Roo.util.Observable
11223 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11224 * either to a configured URL, or to a URL specified at request time.<br><br>
11226 * Requests made by this class are asynchronous, and will return immediately. No data from
11227 * the server will be available to the statement immediately following the {@link #request} call.
11228 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11230 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11231 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11232 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11233 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11234 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11235 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11236 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11237 * standard DOM methods.
11239 * @param {Object} config a configuration object.
11241 Roo.data.Connection = function(config){
11242 Roo.apply(this, config);
11245 * @event beforerequest
11246 * Fires before a network request is made to retrieve a data object.
11247 * @param {Connection} conn This Connection object.
11248 * @param {Object} options The options config object passed to the {@link #request} method.
11250 "beforerequest" : true,
11252 * @event requestcomplete
11253 * Fires if the request was successfully completed.
11254 * @param {Connection} conn This Connection object.
11255 * @param {Object} response The XHR object containing the response data.
11256 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11257 * @param {Object} options The options config object passed to the {@link #request} method.
11259 "requestcomplete" : true,
11261 * @event requestexception
11262 * Fires if an error HTTP status was returned from the server.
11263 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11264 * @param {Connection} conn This Connection object.
11265 * @param {Object} response The XHR object containing the response data.
11266 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11267 * @param {Object} options The options config object passed to the {@link #request} method.
11269 "requestexception" : true
11271 Roo.data.Connection.superclass.constructor.call(this);
11274 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11276 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11279 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11280 * extra parameters to each request made by this object. (defaults to undefined)
11283 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11284 * to each request made by this object. (defaults to undefined)
11287 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11290 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11294 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11300 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11303 disableCaching: true,
11306 * Sends an HTTP request to a remote server.
11307 * @param {Object} options An object which may contain the following properties:<ul>
11308 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11309 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11310 * request, a url encoded string or a function to call to get either.</li>
11311 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11312 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11313 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11314 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11315 * <li>options {Object} The parameter to the request call.</li>
11316 * <li>success {Boolean} True if the request succeeded.</li>
11317 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11319 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11320 * The callback is passed the following parameters:<ul>
11321 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11322 * <li>options {Object} The parameter to the request call.</li>
11324 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11325 * The callback is passed the following parameters:<ul>
11326 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11327 * <li>options {Object} The parameter to the request call.</li>
11329 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11330 * for the callback function. Defaults to the browser window.</li>
11331 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11332 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11333 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11334 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11335 * params for the post data. Any params will be appended to the URL.</li>
11336 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11338 * @return {Number} transactionId
11340 request : function(o){
11341 if(this.fireEvent("beforerequest", this, o) !== false){
11344 if(typeof p == "function"){
11345 p = p.call(o.scope||window, o);
11347 if(typeof p == "object"){
11348 p = Roo.urlEncode(o.params);
11350 if(this.extraParams){
11351 var extras = Roo.urlEncode(this.extraParams);
11352 p = p ? (p + '&' + extras) : extras;
11355 var url = o.url || this.url;
11356 if(typeof url == 'function'){
11357 url = url.call(o.scope||window, o);
11361 var form = Roo.getDom(o.form);
11362 url = url || form.action;
11364 var enctype = form.getAttribute("enctype");
11365 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11366 return this.doFormUpload(o, p, url);
11368 var f = Roo.lib.Ajax.serializeForm(form);
11369 p = p ? (p + '&' + f) : f;
11372 var hs = o.headers;
11373 if(this.defaultHeaders){
11374 hs = Roo.apply(hs || {}, this.defaultHeaders);
11381 success: this.handleResponse,
11382 failure: this.handleFailure,
11384 argument: {options: o},
11385 timeout : this.timeout
11388 var method = o.method||this.method||(p ? "POST" : "GET");
11390 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11391 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11394 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11398 }else if(this.autoAbort !== false){
11402 if((method == 'GET' && p) || o.xmlData){
11403 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11406 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11407 return this.transId;
11409 Roo.callback(o.callback, o.scope, [o, null, null]);
11415 * Determine whether this object has a request outstanding.
11416 * @param {Number} transactionId (Optional) defaults to the last transaction
11417 * @return {Boolean} True if there is an outstanding request.
11419 isLoading : function(transId){
11421 return Roo.lib.Ajax.isCallInProgress(transId);
11423 return this.transId ? true : false;
11428 * Aborts any outstanding request.
11429 * @param {Number} transactionId (Optional) defaults to the last transaction
11431 abort : function(transId){
11432 if(transId || this.isLoading()){
11433 Roo.lib.Ajax.abort(transId || this.transId);
11438 handleResponse : function(response){
11439 this.transId = false;
11440 var options = response.argument.options;
11441 response.argument = options ? options.argument : null;
11442 this.fireEvent("requestcomplete", this, response, options);
11443 Roo.callback(options.success, options.scope, [response, options]);
11444 Roo.callback(options.callback, options.scope, [options, true, response]);
11448 handleFailure : function(response, e){
11449 this.transId = false;
11450 var options = response.argument.options;
11451 response.argument = options ? options.argument : null;
11452 this.fireEvent("requestexception", this, response, options, e);
11453 Roo.callback(options.failure, options.scope, [response, options]);
11454 Roo.callback(options.callback, options.scope, [options, false, response]);
11458 doFormUpload : function(o, ps, url){
11460 var frame = document.createElement('iframe');
11463 frame.className = 'x-hidden';
11465 frame.src = Roo.SSL_SECURE_URL;
11467 document.body.appendChild(frame);
11470 document.frames[id].name = id;
11473 var form = Roo.getDom(o.form);
11475 form.method = 'POST';
11476 form.enctype = form.encoding = 'multipart/form-data';
11482 if(ps){ // add dynamic params
11484 ps = Roo.urlDecode(ps, false);
11486 if(ps.hasOwnProperty(k)){
11487 hd = document.createElement('input');
11488 hd.type = 'hidden';
11491 form.appendChild(hd);
11498 var r = { // bogus response object
11503 r.argument = o ? o.argument : null;
11508 doc = frame.contentWindow.document;
11510 doc = (frame.contentDocument || window.frames[id].document);
11512 if(doc && doc.body){
11513 r.responseText = doc.body.innerHTML;
11515 if(doc && doc.XMLDocument){
11516 r.responseXML = doc.XMLDocument;
11518 r.responseXML = doc;
11525 Roo.EventManager.removeListener(frame, 'load', cb, this);
11527 this.fireEvent("requestcomplete", this, r, o);
11528 Roo.callback(o.success, o.scope, [r, o]);
11529 Roo.callback(o.callback, o.scope, [o, true, r]);
11531 setTimeout(function(){document.body.removeChild(frame);}, 100);
11534 Roo.EventManager.on(frame, 'load', cb, this);
11537 if(hiddens){ // remove dynamic params
11538 for(var i = 0, len = hiddens.length; i < len; i++){
11539 form.removeChild(hiddens[i]);
11547 * @extends Roo.data.Connection
11548 * Global Ajax request class.
11552 Roo.Ajax = new Roo.data.Connection({
11555 * @cfg {String} url @hide
11558 * @cfg {Object} extraParams @hide
11561 * @cfg {Object} defaultHeaders @hide
11564 * @cfg {String} method (Optional) @hide
11567 * @cfg {Number} timeout (Optional) @hide
11570 * @cfg {Boolean} autoAbort (Optional) @hide
11574 * @cfg {Boolean} disableCaching (Optional) @hide
11578 * @property disableCaching
11579 * True to add a unique cache-buster param to GET requests. (defaults to true)
11584 * The default URL to be used for requests to the server. (defaults to undefined)
11588 * @property extraParams
11589 * An object containing properties which are used as
11590 * extra parameters to each request made by this object. (defaults to undefined)
11594 * @property defaultHeaders
11595 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11600 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11604 * @property timeout
11605 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11610 * @property autoAbort
11611 * Whether a new request should abort any pending requests. (defaults to false)
11617 * Serialize the passed form into a url encoded string
11618 * @param {String/HTMLElement} form
11621 serializeForm : function(form){
11622 return Roo.lib.Ajax.serializeForm(form);
11626 * Ext JS Library 1.1.1
11627 * Copyright(c) 2006-2007, Ext JS, LLC.
11629 * Originally Released Under LGPL - original licence link has changed is not relivant.
11632 * <script type="text/javascript">
11636 * Global Ajax request class.
11639 * @extends Roo.data.Connection
11642 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11643 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11644 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11645 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11646 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11647 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11648 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11650 Roo.Ajax = new Roo.data.Connection({
11659 * Serialize the passed form into a url encoded string
11661 * @param {String/HTMLElement} form
11664 serializeForm : function(form){
11665 return Roo.lib.Ajax.serializeForm(form);
11669 * Ext JS Library 1.1.1
11670 * Copyright(c) 2006-2007, Ext JS, LLC.
11672 * Originally Released Under LGPL - original licence link has changed is not relivant.
11675 * <script type="text/javascript">
11680 * @class Roo.UpdateManager
11681 * @extends Roo.util.Observable
11682 * Provides AJAX-style update for Element object.<br><br>
11685 * // Get it from a Roo.Element object
11686 * var el = Roo.get("foo");
11687 * var mgr = el.getUpdateManager();
11688 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11690 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11692 * // or directly (returns the same UpdateManager instance)
11693 * var mgr = new Roo.UpdateManager("myElementId");
11694 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11695 * mgr.on("update", myFcnNeedsToKnow);
11697 // short handed call directly from the element object
11698 Roo.get("foo").load({
11702 text: "Loading Foo..."
11706 * Create new UpdateManager directly.
11707 * @param {String/HTMLElement/Roo.Element} el The element to update
11708 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11710 Roo.UpdateManager = function(el, forceNew){
11712 if(!forceNew && el.updateManager){
11713 return el.updateManager;
11716 * The Element object
11717 * @type Roo.Element
11721 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11724 this.defaultUrl = null;
11728 * @event beforeupdate
11729 * Fired before an update is made, return false from your handler and the update is cancelled.
11730 * @param {Roo.Element} el
11731 * @param {String/Object/Function} url
11732 * @param {String/Object} params
11734 "beforeupdate": true,
11737 * Fired after successful update is made.
11738 * @param {Roo.Element} el
11739 * @param {Object} oResponseObject The response Object
11744 * Fired on update failure.
11745 * @param {Roo.Element} el
11746 * @param {Object} oResponseObject The response Object
11750 var d = Roo.UpdateManager.defaults;
11752 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11755 this.sslBlankUrl = d.sslBlankUrl;
11757 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11760 this.disableCaching = d.disableCaching;
11762 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11765 this.indicatorText = d.indicatorText;
11767 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11770 this.showLoadIndicator = d.showLoadIndicator;
11772 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11775 this.timeout = d.timeout;
11778 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11781 this.loadScripts = d.loadScripts;
11784 * Transaction object of current executing transaction
11786 this.transaction = null;
11791 this.autoRefreshProcId = null;
11793 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11796 this.refreshDelegate = this.refresh.createDelegate(this);
11798 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11801 this.updateDelegate = this.update.createDelegate(this);
11803 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11806 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11810 this.successDelegate = this.processSuccess.createDelegate(this);
11814 this.failureDelegate = this.processFailure.createDelegate(this);
11816 if(!this.renderer){
11818 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11820 this.renderer = new Roo.UpdateManager.BasicRenderer();
11823 Roo.UpdateManager.superclass.constructor.call(this);
11826 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11828 * Get the Element this UpdateManager is bound to
11829 * @return {Roo.Element} The element
11831 getEl : function(){
11835 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11836 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11839 url: "your-url.php",<br/>
11840 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11841 callback: yourFunction,<br/>
11842 scope: yourObject, //(optional scope) <br/>
11843 discardUrl: false, <br/>
11844 nocache: false,<br/>
11845 text: "Loading...",<br/>
11847 scripts: false<br/>
11850 * The only required property is url. The optional properties nocache, text and scripts
11851 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11852 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11853 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11854 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11856 update : function(url, params, callback, discardUrl){
11857 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11858 var method = this.method, cfg;
11859 if(typeof url == "object"){ // must be config object
11862 params = params || cfg.params;
11863 callback = callback || cfg.callback;
11864 discardUrl = discardUrl || cfg.discardUrl;
11865 if(callback && cfg.scope){
11866 callback = callback.createDelegate(cfg.scope);
11868 if(typeof cfg.method != "undefined"){method = cfg.method;};
11869 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11870 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11871 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11872 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11874 this.showLoading();
11876 this.defaultUrl = url;
11878 if(typeof url == "function"){
11879 url = url.call(this);
11882 method = method || (params ? "POST" : "GET");
11883 if(method == "GET"){
11884 url = this.prepareUrl(url);
11887 var o = Roo.apply(cfg ||{}, {
11890 success: this.successDelegate,
11891 failure: this.failureDelegate,
11892 callback: undefined,
11893 timeout: (this.timeout*1000),
11894 argument: {"url": url, "form": null, "callback": callback, "params": params}
11897 this.transaction = Roo.Ajax.request(o);
11902 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11903 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11904 * @param {String/HTMLElement} form The form Id or form element
11905 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11906 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11907 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11909 formUpdate : function(form, url, reset, callback){
11910 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11911 if(typeof url == "function"){
11912 url = url.call(this);
11914 form = Roo.getDom(form);
11915 this.transaction = Roo.Ajax.request({
11918 success: this.successDelegate,
11919 failure: this.failureDelegate,
11920 timeout: (this.timeout*1000),
11921 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11923 this.showLoading.defer(1, this);
11928 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11929 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11931 refresh : function(callback){
11932 if(this.defaultUrl == null){
11935 this.update(this.defaultUrl, null, callback, true);
11939 * Set this element to auto refresh.
11940 * @param {Number} interval How often to update (in seconds).
11941 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11942 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11943 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11944 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11946 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11948 this.update(url || this.defaultUrl, params, callback, true);
11950 if(this.autoRefreshProcId){
11951 clearInterval(this.autoRefreshProcId);
11953 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11957 * Stop auto refresh on this element.
11959 stopAutoRefresh : function(){
11960 if(this.autoRefreshProcId){
11961 clearInterval(this.autoRefreshProcId);
11962 delete this.autoRefreshProcId;
11966 isAutoRefreshing : function(){
11967 return this.autoRefreshProcId ? true : false;
11970 * Called to update the element to "Loading" state. Override to perform custom action.
11972 showLoading : function(){
11973 if(this.showLoadIndicator){
11974 this.el.update(this.indicatorText);
11979 * Adds unique parameter to query string if disableCaching = true
11982 prepareUrl : function(url){
11983 if(this.disableCaching){
11984 var append = "_dc=" + (new Date().getTime());
11985 if(url.indexOf("?") !== -1){
11986 url += "&" + append;
11988 url += "?" + append;
11997 processSuccess : function(response){
11998 this.transaction = null;
11999 if(response.argument.form && response.argument.reset){
12000 try{ // put in try/catch since some older FF releases had problems with this
12001 response.argument.form.reset();
12004 if(this.loadScripts){
12005 this.renderer.render(this.el, response, this,
12006 this.updateComplete.createDelegate(this, [response]));
12008 this.renderer.render(this.el, response, this);
12009 this.updateComplete(response);
12013 updateComplete : function(response){
12014 this.fireEvent("update", this.el, response);
12015 if(typeof response.argument.callback == "function"){
12016 response.argument.callback(this.el, true, response);
12023 processFailure : function(response){
12024 this.transaction = null;
12025 this.fireEvent("failure", this.el, response);
12026 if(typeof response.argument.callback == "function"){
12027 response.argument.callback(this.el, false, response);
12032 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12033 * @param {Object} renderer The object implementing the render() method
12035 setRenderer : function(renderer){
12036 this.renderer = renderer;
12039 getRenderer : function(){
12040 return this.renderer;
12044 * Set the defaultUrl used for updates
12045 * @param {String/Function} defaultUrl The url or a function to call to get the url
12047 setDefaultUrl : function(defaultUrl){
12048 this.defaultUrl = defaultUrl;
12052 * Aborts the executing transaction
12054 abort : function(){
12055 if(this.transaction){
12056 Roo.Ajax.abort(this.transaction);
12061 * Returns true if an update is in progress
12062 * @return {Boolean}
12064 isUpdating : function(){
12065 if(this.transaction){
12066 return Roo.Ajax.isLoading(this.transaction);
12073 * @class Roo.UpdateManager.defaults
12074 * @static (not really - but it helps the doc tool)
12075 * The defaults collection enables customizing the default properties of UpdateManager
12077 Roo.UpdateManager.defaults = {
12079 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12085 * True to process scripts by default (Defaults to false).
12088 loadScripts : false,
12091 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12094 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12096 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12099 disableCaching : false,
12101 * Whether to show indicatorText when loading (Defaults to true).
12104 showLoadIndicator : true,
12106 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12109 indicatorText : '<div class="loading-indicator">Loading...</div>'
12113 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12115 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12116 * @param {String/HTMLElement/Roo.Element} el The element to update
12117 * @param {String} url The url
12118 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12119 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12122 * @member Roo.UpdateManager
12124 Roo.UpdateManager.updateElement = function(el, url, params, options){
12125 var um = Roo.get(el, true).getUpdateManager();
12126 Roo.apply(um, options);
12127 um.update(url, params, options ? options.callback : null);
12129 // alias for backwards compat
12130 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12132 * @class Roo.UpdateManager.BasicRenderer
12133 * Default Content renderer. Updates the elements innerHTML with the responseText.
12135 Roo.UpdateManager.BasicRenderer = function(){};
12137 Roo.UpdateManager.BasicRenderer.prototype = {
12139 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12140 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12141 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12142 * @param {Roo.Element} el The element being rendered
12143 * @param {Object} response The YUI Connect response object
12144 * @param {UpdateManager} updateManager The calling update manager
12145 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12147 render : function(el, response, updateManager, callback){
12148 el.update(response.responseText, updateManager.loadScripts, callback);
12153 * Ext JS Library 1.1.1
12154 * Copyright(c) 2006-2007, Ext JS, LLC.
12156 * Originally Released Under LGPL - original licence link has changed is not relivant.
12159 * <script type="text/javascript">
12163 * @class Roo.util.DelayedTask
12164 * Provides a convenient method of performing setTimeout where a new
12165 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12166 * You can use this class to buffer
12167 * the keypress events for a certain number of milliseconds, and perform only if they stop
12168 * for that amount of time.
12169 * @constructor The parameters to this constructor serve as defaults and are not required.
12170 * @param {Function} fn (optional) The default function to timeout
12171 * @param {Object} scope (optional) The default scope of that timeout
12172 * @param {Array} args (optional) The default Array of arguments
12174 Roo.util.DelayedTask = function(fn, scope, args){
12175 var id = null, d, t;
12177 var call = function(){
12178 var now = new Date().getTime();
12182 fn.apply(scope, args || []);
12186 * Cancels any pending timeout and queues a new one
12187 * @param {Number} delay The milliseconds to delay
12188 * @param {Function} newFn (optional) Overrides function passed to constructor
12189 * @param {Object} newScope (optional) Overrides scope passed to constructor
12190 * @param {Array} newArgs (optional) Overrides args passed to constructor
12192 this.delay = function(delay, newFn, newScope, newArgs){
12193 if(id && delay != d){
12197 t = new Date().getTime();
12199 scope = newScope || scope;
12200 args = newArgs || args;
12202 id = setInterval(call, d);
12207 * Cancel the last queued timeout
12209 this.cancel = function(){
12217 * Ext JS Library 1.1.1
12218 * Copyright(c) 2006-2007, Ext JS, LLC.
12220 * Originally Released Under LGPL - original licence link has changed is not relivant.
12223 * <script type="text/javascript">
12227 Roo.util.TaskRunner = function(interval){
12228 interval = interval || 10;
12229 var tasks = [], removeQueue = [];
12231 var running = false;
12233 var stopThread = function(){
12239 var startThread = function(){
12242 id = setInterval(runTasks, interval);
12246 var removeTask = function(task){
12247 removeQueue.push(task);
12253 var runTasks = function(){
12254 if(removeQueue.length > 0){
12255 for(var i = 0, len = removeQueue.length; i < len; i++){
12256 tasks.remove(removeQueue[i]);
12259 if(tasks.length < 1){
12264 var now = new Date().getTime();
12265 for(var i = 0, len = tasks.length; i < len; ++i){
12267 var itime = now - t.taskRunTime;
12268 if(t.interval <= itime){
12269 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12270 t.taskRunTime = now;
12271 if(rt === false || t.taskRunCount === t.repeat){
12276 if(t.duration && t.duration <= (now - t.taskStartTime)){
12283 * Queues a new task.
12284 * @param {Object} task
12286 this.start = function(task){
12288 task.taskStartTime = new Date().getTime();
12289 task.taskRunTime = 0;
12290 task.taskRunCount = 0;
12295 this.stop = function(task){
12300 this.stopAll = function(){
12302 for(var i = 0, len = tasks.length; i < len; i++){
12303 if(tasks[i].onStop){
12312 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12314 * Ext JS Library 1.1.1
12315 * Copyright(c) 2006-2007, Ext JS, LLC.
12317 * Originally Released Under LGPL - original licence link has changed is not relivant.
12320 * <script type="text/javascript">
12325 * @class Roo.util.MixedCollection
12326 * @extends Roo.util.Observable
12327 * A Collection class that maintains both numeric indexes and keys and exposes events.
12329 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12330 * collection (defaults to false)
12331 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12332 * and return the key value for that item. This is used when available to look up the key on items that
12333 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12334 * equivalent to providing an implementation for the {@link #getKey} method.
12336 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12344 * Fires when the collection is cleared.
12349 * Fires when an item is added to the collection.
12350 * @param {Number} index The index at which the item was added.
12351 * @param {Object} o The item added.
12352 * @param {String} key The key associated with the added item.
12357 * Fires when an item is replaced in the collection.
12358 * @param {String} key he key associated with the new added.
12359 * @param {Object} old The item being replaced.
12360 * @param {Object} new The new item.
12365 * Fires when an item is removed from the collection.
12366 * @param {Object} o The item being removed.
12367 * @param {String} key (optional) The key associated with the removed item.
12372 this.allowFunctions = allowFunctions === true;
12374 this.getKey = keyFn;
12376 Roo.util.MixedCollection.superclass.constructor.call(this);
12379 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12380 allowFunctions : false,
12383 * Adds an item to the collection.
12384 * @param {String} key The key to associate with the item
12385 * @param {Object} o The item to add.
12386 * @return {Object} The item added.
12388 add : function(key, o){
12389 if(arguments.length == 1){
12391 key = this.getKey(o);
12393 if(typeof key == "undefined" || key === null){
12395 this.items.push(o);
12396 this.keys.push(null);
12398 var old = this.map[key];
12400 return this.replace(key, o);
12403 this.items.push(o);
12405 this.keys.push(key);
12407 this.fireEvent("add", this.length-1, o, key);
12412 * MixedCollection has a generic way to fetch keys if you implement getKey.
12415 var mc = new Roo.util.MixedCollection();
12416 mc.add(someEl.dom.id, someEl);
12417 mc.add(otherEl.dom.id, otherEl);
12421 var mc = new Roo.util.MixedCollection();
12422 mc.getKey = function(el){
12428 // or via the constructor
12429 var mc = new Roo.util.MixedCollection(false, function(el){
12435 * @param o {Object} The item for which to find the key.
12436 * @return {Object} The key for the passed item.
12438 getKey : function(o){
12443 * Replaces an item in the collection.
12444 * @param {String} key The key associated with the item to replace, or the item to replace.
12445 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12446 * @return {Object} The new item.
12448 replace : function(key, o){
12449 if(arguments.length == 1){
12451 key = this.getKey(o);
12453 var old = this.item(key);
12454 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12455 return this.add(key, o);
12457 var index = this.indexOfKey(key);
12458 this.items[index] = o;
12460 this.fireEvent("replace", key, old, o);
12465 * Adds all elements of an Array or an Object to the collection.
12466 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12467 * an Array of values, each of which are added to the collection.
12469 addAll : function(objs){
12470 if(arguments.length > 1 || objs instanceof Array){
12471 var args = arguments.length > 1 ? arguments : objs;
12472 for(var i = 0, len = args.length; i < len; i++){
12476 for(var key in objs){
12477 if(this.allowFunctions || typeof objs[key] != "function"){
12478 this.add(key, objs[key]);
12485 * Executes the specified function once for every item in the collection, passing each
12486 * item as the first and only parameter. returning false from the function will stop the iteration.
12487 * @param {Function} fn The function to execute for each item.
12488 * @param {Object} scope (optional) The scope in which to execute the function.
12490 each : function(fn, scope){
12491 var items = [].concat(this.items); // each safe for removal
12492 for(var i = 0, len = items.length; i < len; i++){
12493 if(fn.call(scope || items[i], items[i], i, len) === false){
12500 * Executes the specified function once for every key in the collection, passing each
12501 * key, and its associated item as the first two parameters.
12502 * @param {Function} fn The function to execute for each item.
12503 * @param {Object} scope (optional) The scope in which to execute the function.
12505 eachKey : function(fn, scope){
12506 for(var i = 0, len = this.keys.length; i < len; i++){
12507 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12512 * Returns the first item in the collection which elicits a true return value from the
12513 * passed selection function.
12514 * @param {Function} fn The selection function to execute for each item.
12515 * @param {Object} scope (optional) The scope in which to execute the function.
12516 * @return {Object} The first item in the collection which returned true from the selection function.
12518 find : function(fn, scope){
12519 for(var i = 0, len = this.items.length; i < len; i++){
12520 if(fn.call(scope || window, this.items[i], this.keys[i])){
12521 return this.items[i];
12528 * Inserts an item at the specified index in the collection.
12529 * @param {Number} index The index to insert the item at.
12530 * @param {String} key The key to associate with the new item, or the item itself.
12531 * @param {Object} o (optional) If the second parameter was a key, the new item.
12532 * @return {Object} The item inserted.
12534 insert : function(index, key, o){
12535 if(arguments.length == 2){
12537 key = this.getKey(o);
12539 if(index >= this.length){
12540 return this.add(key, o);
12543 this.items.splice(index, 0, o);
12544 if(typeof key != "undefined" && key != null){
12547 this.keys.splice(index, 0, key);
12548 this.fireEvent("add", index, o, key);
12553 * Removed an item from the collection.
12554 * @param {Object} o The item to remove.
12555 * @return {Object} The item removed.
12557 remove : function(o){
12558 return this.removeAt(this.indexOf(o));
12562 * Remove an item from a specified index in the collection.
12563 * @param {Number} index The index within the collection of the item to remove.
12565 removeAt : function(index){
12566 if(index < this.length && index >= 0){
12568 var o = this.items[index];
12569 this.items.splice(index, 1);
12570 var key = this.keys[index];
12571 if(typeof key != "undefined"){
12572 delete this.map[key];
12574 this.keys.splice(index, 1);
12575 this.fireEvent("remove", o, key);
12580 * Removed an item associated with the passed key fom the collection.
12581 * @param {String} key The key of the item to remove.
12583 removeKey : function(key){
12584 return this.removeAt(this.indexOfKey(key));
12588 * Returns the number of items in the collection.
12589 * @return {Number} the number of items in the collection.
12591 getCount : function(){
12592 return this.length;
12596 * Returns index within the collection of the passed Object.
12597 * @param {Object} o The item to find the index of.
12598 * @return {Number} index of the item.
12600 indexOf : function(o){
12601 if(!this.items.indexOf){
12602 for(var i = 0, len = this.items.length; i < len; i++){
12603 if(this.items[i] == o) return i;
12607 return this.items.indexOf(o);
12612 * Returns index within the collection of the passed key.
12613 * @param {String} key The key to find the index of.
12614 * @return {Number} index of the key.
12616 indexOfKey : function(key){
12617 if(!this.keys.indexOf){
12618 for(var i = 0, len = this.keys.length; i < len; i++){
12619 if(this.keys[i] == key) return i;
12623 return this.keys.indexOf(key);
12628 * Returns the item associated with the passed key OR index. Key has priority over index.
12629 * @param {String/Number} key The key or index of the item.
12630 * @return {Object} The item associated with the passed key.
12632 item : function(key){
12633 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12634 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12638 * Returns the item at the specified index.
12639 * @param {Number} index The index of the item.
12642 itemAt : function(index){
12643 return this.items[index];
12647 * Returns the item associated with the passed key.
12648 * @param {String/Number} key The key of the item.
12649 * @return {Object} The item associated with the passed key.
12651 key : function(key){
12652 return this.map[key];
12656 * Returns true if the collection contains the passed Object as an item.
12657 * @param {Object} o The Object to look for in the collection.
12658 * @return {Boolean} True if the collection contains the Object as an item.
12660 contains : function(o){
12661 return this.indexOf(o) != -1;
12665 * Returns true if the collection contains the passed Object as a key.
12666 * @param {String} key The key to look for in the collection.
12667 * @return {Boolean} True if the collection contains the Object as a key.
12669 containsKey : function(key){
12670 return typeof this.map[key] != "undefined";
12674 * Removes all items from the collection.
12676 clear : function(){
12681 this.fireEvent("clear");
12685 * Returns the first item in the collection.
12686 * @return {Object} the first item in the collection..
12688 first : function(){
12689 return this.items[0];
12693 * Returns the last item in the collection.
12694 * @return {Object} the last item in the collection..
12697 return this.items[this.length-1];
12700 _sort : function(property, dir, fn){
12701 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12702 fn = fn || function(a, b){
12705 var c = [], k = this.keys, items = this.items;
12706 for(var i = 0, len = items.length; i < len; i++){
12707 c[c.length] = {key: k[i], value: items[i], index: i};
12709 c.sort(function(a, b){
12710 var v = fn(a[property], b[property]) * dsc;
12712 v = (a.index < b.index ? -1 : 1);
12716 for(var i = 0, len = c.length; i < len; i++){
12717 items[i] = c[i].value;
12720 this.fireEvent("sort", this);
12724 * Sorts this collection with the passed comparison function
12725 * @param {String} direction (optional) "ASC" or "DESC"
12726 * @param {Function} fn (optional) comparison function
12728 sort : function(dir, fn){
12729 this._sort("value", dir, fn);
12733 * Sorts this collection by keys
12734 * @param {String} direction (optional) "ASC" or "DESC"
12735 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12737 keySort : function(dir, fn){
12738 this._sort("key", dir, fn || function(a, b){
12739 return String(a).toUpperCase()-String(b).toUpperCase();
12744 * Returns a range of items in this collection
12745 * @param {Number} startIndex (optional) defaults to 0
12746 * @param {Number} endIndex (optional) default to the last item
12747 * @return {Array} An array of items
12749 getRange : function(start, end){
12750 var items = this.items;
12751 if(items.length < 1){
12754 start = start || 0;
12755 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12758 for(var i = start; i <= end; i++) {
12759 r[r.length] = items[i];
12762 for(var i = start; i >= end; i--) {
12763 r[r.length] = items[i];
12770 * Filter the <i>objects</i> in this collection by a specific property.
12771 * Returns a new collection that has been filtered.
12772 * @param {String} property A property on your objects
12773 * @param {String/RegExp} value Either string that the property values
12774 * should start with or a RegExp to test against the property
12775 * @return {MixedCollection} The new filtered collection
12777 filter : function(property, value){
12778 if(!value.exec){ // not a regex
12779 value = String(value);
12780 if(value.length == 0){
12781 return this.clone();
12783 value = new RegExp("^" + Roo.escapeRe(value), "i");
12785 return this.filterBy(function(o){
12786 return o && value.test(o[property]);
12791 * Filter by a function. * Returns a new collection that has been filtered.
12792 * The passed function will be called with each
12793 * object in the collection. If the function returns true, the value is included
12794 * otherwise it is filtered.
12795 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12796 * @param {Object} scope (optional) The scope of the function (defaults to this)
12797 * @return {MixedCollection} The new filtered collection
12799 filterBy : function(fn, scope){
12800 var r = new Roo.util.MixedCollection();
12801 r.getKey = this.getKey;
12802 var k = this.keys, it = this.items;
12803 for(var i = 0, len = it.length; i < len; i++){
12804 if(fn.call(scope||this, it[i], k[i])){
12805 r.add(k[i], it[i]);
12812 * Creates a duplicate of this collection
12813 * @return {MixedCollection}
12815 clone : function(){
12816 var r = new Roo.util.MixedCollection();
12817 var k = this.keys, it = this.items;
12818 for(var i = 0, len = it.length; i < len; i++){
12819 r.add(k[i], it[i]);
12821 r.getKey = this.getKey;
12826 * Returns the item associated with the passed key or index.
12828 * @param {String/Number} key The key or index of the item.
12829 * @return {Object} The item associated with the passed key.
12831 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12833 * Ext JS Library 1.1.1
12834 * Copyright(c) 2006-2007, Ext JS, LLC.
12836 * Originally Released Under LGPL - original licence link has changed is not relivant.
12839 * <script type="text/javascript">
12842 * @class Roo.util.JSON
12843 * Modified version of Douglas Crockford"s json.js that doesn"t
12844 * mess with the Object prototype
12845 * http://www.json.org/js.html
12848 Roo.util.JSON = new (function(){
12849 var useHasOwn = {}.hasOwnProperty ? true : false;
12851 // crashes Safari in some instances
12852 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12854 var pad = function(n) {
12855 return n < 10 ? "0" + n : n;
12868 var encodeString = function(s){
12869 if (/["\\\x00-\x1f]/.test(s)) {
12870 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12875 c = b.charCodeAt();
12877 Math.floor(c / 16).toString(16) +
12878 (c % 16).toString(16);
12881 return '"' + s + '"';
12884 var encodeArray = function(o){
12885 var a = ["["], b, i, l = o.length, v;
12886 for (i = 0; i < l; i += 1) {
12888 switch (typeof v) {
12897 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12905 var encodeDate = function(o){
12906 return '"' + o.getFullYear() + "-" +
12907 pad(o.getMonth() + 1) + "-" +
12908 pad(o.getDate()) + "T" +
12909 pad(o.getHours()) + ":" +
12910 pad(o.getMinutes()) + ":" +
12911 pad(o.getSeconds()) + '"';
12915 * Encodes an Object, Array or other value
12916 * @param {Mixed} o The variable to encode
12917 * @return {String} The JSON string
12919 this.encode = function(o)
12921 // should this be extended to fully wrap stringify..
12923 if(typeof o == "undefined" || o === null){
12925 }else if(o instanceof Array){
12926 return encodeArray(o);
12927 }else if(o instanceof Date){
12928 return encodeDate(o);
12929 }else if(typeof o == "string"){
12930 return encodeString(o);
12931 }else if(typeof o == "number"){
12932 return isFinite(o) ? String(o) : "null";
12933 }else if(typeof o == "boolean"){
12936 var a = ["{"], b, i, v;
12938 if(!useHasOwn || o.hasOwnProperty(i)) {
12940 switch (typeof v) {
12949 a.push(this.encode(i), ":",
12950 v === null ? "null" : this.encode(v));
12961 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12962 * @param {String} json The JSON string
12963 * @return {Object} The resulting object
12965 this.decode = function(json){
12967 return /** eval:var:json */ eval("(" + json + ')');
12971 * Shorthand for {@link Roo.util.JSON#encode}
12972 * @member Roo encode
12974 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12976 * Shorthand for {@link Roo.util.JSON#decode}
12977 * @member Roo decode
12979 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12982 * Ext JS Library 1.1.1
12983 * Copyright(c) 2006-2007, Ext JS, LLC.
12985 * Originally Released Under LGPL - original licence link has changed is not relivant.
12988 * <script type="text/javascript">
12992 * @class Roo.util.Format
12993 * Reusable data formatting functions
12996 Roo.util.Format = function(){
12997 var trimRe = /^\s+|\s+$/g;
13000 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13001 * @param {String} value The string to truncate
13002 * @param {Number} length The maximum length to allow before truncating
13003 * @return {String} The converted text
13005 ellipsis : function(value, len){
13006 if(value && value.length > len){
13007 return value.substr(0, len-3)+"...";
13013 * Checks a reference and converts it to empty string if it is undefined
13014 * @param {Mixed} value Reference to check
13015 * @return {Mixed} Empty string if converted, otherwise the original value
13017 undef : function(value){
13018 return typeof value != "undefined" ? value : "";
13022 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13023 * @param {String} value The string to encode
13024 * @return {String} The encoded text
13026 htmlEncode : function(value){
13027 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13031 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13032 * @param {String} value The string to decode
13033 * @return {String} The decoded text
13035 htmlDecode : function(value){
13036 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13040 * Trims any whitespace from either side of a string
13041 * @param {String} value The text to trim
13042 * @return {String} The trimmed text
13044 trim : function(value){
13045 return String(value).replace(trimRe, "");
13049 * Returns a substring from within an original string
13050 * @param {String} value The original text
13051 * @param {Number} start The start index of the substring
13052 * @param {Number} length The length of the substring
13053 * @return {String} The substring
13055 substr : function(value, start, length){
13056 return String(value).substr(start, length);
13060 * Converts a string to all lower case letters
13061 * @param {String} value The text to convert
13062 * @return {String} The converted text
13064 lowercase : function(value){
13065 return String(value).toLowerCase();
13069 * Converts a string to all upper case letters
13070 * @param {String} value The text to convert
13071 * @return {String} The converted text
13073 uppercase : function(value){
13074 return String(value).toUpperCase();
13078 * Converts the first character only of a string to upper case
13079 * @param {String} value The text to convert
13080 * @return {String} The converted text
13082 capitalize : function(value){
13083 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13087 call : function(value, fn){
13088 if(arguments.length > 2){
13089 var args = Array.prototype.slice.call(arguments, 2);
13090 args.unshift(value);
13092 return /** eval:var:value */ eval(fn).apply(window, args);
13094 /** eval:var:value */
13095 return /** eval:var:value */ eval(fn).call(window, value);
13101 * safer version of Math.toFixed..??/
13102 * @param {Number/String} value The numeric value to format
13103 * @param {Number/String} value Decimal places
13104 * @return {String} The formatted currency string
13106 toFixed : function(v, n)
13108 // why not use to fixed - precision is buggered???
13110 return Math.round(v-0);
13112 var fact = Math.pow(10,n+1);
13113 v = (Math.round((v-0)*fact))/fact;
13114 var z = (''+fact).substring(2);
13115 if (v == Math.floor(v)) {
13116 return Math.floor(v) + '.' + z;
13119 // now just padd decimals..
13120 var ps = String(v).split('.');
13121 var fd = (ps[1] + z);
13122 var r = fd.substring(0,n);
13123 var rm = fd.substring(n);
13125 return ps[0] + '.' + r;
13127 r*=1; // turn it into a number;
13129 if (String(r).length != n) {
13132 r = String(r).substring(1); // chop the end off.
13135 return ps[0] + '.' + r;
13140 * Format a number as US currency
13141 * @param {Number/String} value The numeric value to format
13142 * @return {String} The formatted currency string
13144 usMoney : function(v){
13145 v = (Math.round((v-0)*100))/100;
13146 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13148 var ps = v.split('.');
13150 var sub = ps[1] ? '.'+ ps[1] : '.00';
13151 var r = /(\d+)(\d{3})/;
13152 while (r.test(whole)) {
13153 whole = whole.replace(r, '$1' + ',' + '$2');
13155 return "$" + whole + sub ;
13159 * Parse a value into a formatted date using the specified format pattern.
13160 * @param {Mixed} value The value to format
13161 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13162 * @return {String} The formatted date string
13164 date : function(v, format){
13168 if(!(v instanceof Date)){
13169 v = new Date(Date.parse(v));
13171 return v.dateFormat(format || "m/d/Y");
13175 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13176 * @param {String} format Any valid date format string
13177 * @return {Function} The date formatting function
13179 dateRenderer : function(format){
13180 return function(v){
13181 return Roo.util.Format.date(v, format);
13186 stripTagsRE : /<\/?[^>]+>/gi,
13189 * Strips all HTML tags
13190 * @param {Mixed} value The text from which to strip tags
13191 * @return {String} The stripped text
13193 stripTags : function(v){
13194 return !v ? v : String(v).replace(this.stripTagsRE, "");
13199 * Ext JS Library 1.1.1
13200 * Copyright(c) 2006-2007, Ext JS, LLC.
13202 * Originally Released Under LGPL - original licence link has changed is not relivant.
13205 * <script type="text/javascript">
13212 * @class Roo.MasterTemplate
13213 * @extends Roo.Template
13214 * Provides a template that can have child templates. The syntax is:
13216 var t = new Roo.MasterTemplate(
13217 '<select name="{name}">',
13218 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13221 t.add('options', {value: 'foo', text: 'bar'});
13222 // or you can add multiple child elements in one shot
13223 t.addAll('options', [
13224 {value: 'foo', text: 'bar'},
13225 {value: 'foo2', text: 'bar2'},
13226 {value: 'foo3', text: 'bar3'}
13228 // then append, applying the master template values
13229 t.append('my-form', {name: 'my-select'});
13231 * A name attribute for the child template is not required if you have only one child
13232 * template or you want to refer to them by index.
13234 Roo.MasterTemplate = function(){
13235 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13236 this.originalHtml = this.html;
13238 var m, re = this.subTemplateRe;
13241 while(m = re.exec(this.html)){
13242 var name = m[1], content = m[2];
13247 tpl : new Roo.Template(content)
13250 st[name] = st[subIndex];
13252 st[subIndex].tpl.compile();
13253 st[subIndex].tpl.call = this.call.createDelegate(this);
13256 this.subCount = subIndex;
13259 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13261 * The regular expression used to match sub templates
13265 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13268 * Applies the passed values to a child template.
13269 * @param {String/Number} name (optional) The name or index of the child template
13270 * @param {Array/Object} values The values to be applied to the template
13271 * @return {MasterTemplate} this
13273 add : function(name, values){
13274 if(arguments.length == 1){
13275 values = arguments[0];
13278 var s = this.subs[name];
13279 s.buffer[s.buffer.length] = s.tpl.apply(values);
13284 * Applies all the passed values to a child template.
13285 * @param {String/Number} name (optional) The name or index of the child template
13286 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13287 * @param {Boolean} reset (optional) True to reset the template first
13288 * @return {MasterTemplate} this
13290 fill : function(name, values, reset){
13292 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13300 for(var i = 0, len = values.length; i < len; i++){
13301 this.add(name, values[i]);
13307 * Resets the template for reuse
13308 * @return {MasterTemplate} this
13310 reset : function(){
13312 for(var i = 0; i < this.subCount; i++){
13318 applyTemplate : function(values){
13320 var replaceIndex = -1;
13321 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13322 return s[++replaceIndex].buffer.join("");
13324 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13327 apply : function(){
13328 return this.applyTemplate.apply(this, arguments);
13331 compile : function(){return this;}
13335 * Alias for fill().
13338 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13340 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13341 * var tpl = Roo.MasterTemplate.from('element-id');
13342 * @param {String/HTMLElement} el
13343 * @param {Object} config
13346 Roo.MasterTemplate.from = function(el, config){
13347 el = Roo.getDom(el);
13348 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13351 * Ext JS Library 1.1.1
13352 * Copyright(c) 2006-2007, Ext JS, LLC.
13354 * Originally Released Under LGPL - original licence link has changed is not relivant.
13357 * <script type="text/javascript">
13362 * @class Roo.util.CSS
13363 * Utility class for manipulating CSS rules
13366 Roo.util.CSS = function(){
13368 var doc = document;
13370 var camelRe = /(-[a-z])/gi;
13371 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13375 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13376 * tag and appended to the HEAD of the document.
13377 * @param {String|Object} cssText The text containing the css rules
13378 * @param {String} id An id to add to the stylesheet for later removal
13379 * @return {StyleSheet}
13381 createStyleSheet : function(cssText, id){
13383 var head = doc.getElementsByTagName("head")[0];
13384 var nrules = doc.createElement("style");
13385 nrules.setAttribute("type", "text/css");
13387 nrules.setAttribute("id", id);
13389 if (typeof(cssText) != 'string') {
13390 // support object maps..
13391 // not sure if this a good idea..
13392 // perhaps it should be merged with the general css handling
13393 // and handle js style props.
13394 var cssTextNew = [];
13395 for(var n in cssText) {
13397 for(var k in cssText[n]) {
13398 citems.push( k + ' : ' +cssText[n][k] + ';' );
13400 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13403 cssText = cssTextNew.join("\n");
13409 head.appendChild(nrules);
13410 ss = nrules.styleSheet;
13411 ss.cssText = cssText;
13414 nrules.appendChild(doc.createTextNode(cssText));
13416 nrules.cssText = cssText;
13418 head.appendChild(nrules);
13419 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13421 this.cacheStyleSheet(ss);
13426 * Removes a style or link tag by id
13427 * @param {String} id The id of the tag
13429 removeStyleSheet : function(id){
13430 var existing = doc.getElementById(id);
13432 existing.parentNode.removeChild(existing);
13437 * Dynamically swaps an existing stylesheet reference for a new one
13438 * @param {String} id The id of an existing link tag to remove
13439 * @param {String} url The href of the new stylesheet to include
13441 swapStyleSheet : function(id, url){
13442 this.removeStyleSheet(id);
13443 var ss = doc.createElement("link");
13444 ss.setAttribute("rel", "stylesheet");
13445 ss.setAttribute("type", "text/css");
13446 ss.setAttribute("id", id);
13447 ss.setAttribute("href", url);
13448 doc.getElementsByTagName("head")[0].appendChild(ss);
13452 * Refresh the rule cache if you have dynamically added stylesheets
13453 * @return {Object} An object (hash) of rules indexed by selector
13455 refreshCache : function(){
13456 return this.getRules(true);
13460 cacheStyleSheet : function(stylesheet){
13464 try{// try catch for cross domain access issue
13465 var ssRules = stylesheet.cssRules || stylesheet.rules;
13466 for(var j = ssRules.length-1; j >= 0; --j){
13467 rules[ssRules[j].selectorText] = ssRules[j];
13473 * Gets all css rules for the document
13474 * @param {Boolean} refreshCache true to refresh the internal cache
13475 * @return {Object} An object (hash) of rules indexed by selector
13477 getRules : function(refreshCache){
13478 if(rules == null || refreshCache){
13480 var ds = doc.styleSheets;
13481 for(var i =0, len = ds.length; i < len; i++){
13483 this.cacheStyleSheet(ds[i]);
13491 * Gets an an individual CSS rule by selector(s)
13492 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13493 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13494 * @return {CSSRule} The CSS rule or null if one is not found
13496 getRule : function(selector, refreshCache){
13497 var rs = this.getRules(refreshCache);
13498 if(!(selector instanceof Array)){
13499 return rs[selector];
13501 for(var i = 0; i < selector.length; i++){
13502 if(rs[selector[i]]){
13503 return rs[selector[i]];
13511 * Updates a rule property
13512 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13513 * @param {String} property The css property
13514 * @param {String} value The new value for the property
13515 * @return {Boolean} true If a rule was found and updated
13517 updateRule : function(selector, property, value){
13518 if(!(selector instanceof Array)){
13519 var rule = this.getRule(selector);
13521 rule.style[property.replace(camelRe, camelFn)] = value;
13525 for(var i = 0; i < selector.length; i++){
13526 if(this.updateRule(selector[i], property, value)){
13536 * Ext JS Library 1.1.1
13537 * Copyright(c) 2006-2007, Ext JS, LLC.
13539 * Originally Released Under LGPL - original licence link has changed is not relivant.
13542 * <script type="text/javascript">
13548 * @class Roo.util.ClickRepeater
13549 * @extends Roo.util.Observable
13551 * A wrapper class which can be applied to any element. Fires a "click" event while the
13552 * mouse is pressed. The interval between firings may be specified in the config but
13553 * defaults to 10 milliseconds.
13555 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13557 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13558 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13559 * Similar to an autorepeat key delay.
13560 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13561 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13562 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13563 * "interval" and "delay" are ignored. "immediate" is honored.
13564 * @cfg {Boolean} preventDefault True to prevent the default click event
13565 * @cfg {Boolean} stopDefault True to stop the default click event
13568 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13569 * 2007-02-02 jvs Renamed to ClickRepeater
13570 * 2007-02-03 jvs Modifications for FF Mac and Safari
13573 * @param {String/HTMLElement/Element} el The element to listen on
13574 * @param {Object} config
13576 Roo.util.ClickRepeater = function(el, config)
13578 this.el = Roo.get(el);
13579 this.el.unselectable();
13581 Roo.apply(this, config);
13586 * Fires when the mouse button is depressed.
13587 * @param {Roo.util.ClickRepeater} this
13589 "mousedown" : true,
13592 * Fires on a specified interval during the time the element is pressed.
13593 * @param {Roo.util.ClickRepeater} this
13598 * Fires when the mouse key is released.
13599 * @param {Roo.util.ClickRepeater} this
13604 this.el.on("mousedown", this.handleMouseDown, this);
13605 if(this.preventDefault || this.stopDefault){
13606 this.el.on("click", function(e){
13607 if(this.preventDefault){
13608 e.preventDefault();
13610 if(this.stopDefault){
13616 // allow inline handler
13618 this.on("click", this.handler, this.scope || this);
13621 Roo.util.ClickRepeater.superclass.constructor.call(this);
13624 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13627 preventDefault : true,
13628 stopDefault : false,
13632 handleMouseDown : function(){
13633 clearTimeout(this.timer);
13635 if(this.pressClass){
13636 this.el.addClass(this.pressClass);
13638 this.mousedownTime = new Date();
13640 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13641 this.el.on("mouseout", this.handleMouseOut, this);
13643 this.fireEvent("mousedown", this);
13644 this.fireEvent("click", this);
13646 this.timer = this.click.defer(this.delay || this.interval, this);
13650 click : function(){
13651 this.fireEvent("click", this);
13652 this.timer = this.click.defer(this.getInterval(), this);
13656 getInterval: function(){
13657 if(!this.accelerate){
13658 return this.interval;
13660 var pressTime = this.mousedownTime.getElapsed();
13661 if(pressTime < 500){
13663 }else if(pressTime < 1700){
13665 }else if(pressTime < 2600){
13667 }else if(pressTime < 3500){
13669 }else if(pressTime < 4400){
13671 }else if(pressTime < 5300){
13673 }else if(pressTime < 6200){
13681 handleMouseOut : function(){
13682 clearTimeout(this.timer);
13683 if(this.pressClass){
13684 this.el.removeClass(this.pressClass);
13686 this.el.on("mouseover", this.handleMouseReturn, this);
13690 handleMouseReturn : function(){
13691 this.el.un("mouseover", this.handleMouseReturn);
13692 if(this.pressClass){
13693 this.el.addClass(this.pressClass);
13699 handleMouseUp : function(){
13700 clearTimeout(this.timer);
13701 this.el.un("mouseover", this.handleMouseReturn);
13702 this.el.un("mouseout", this.handleMouseOut);
13703 Roo.get(document).un("mouseup", this.handleMouseUp);
13704 this.el.removeClass(this.pressClass);
13705 this.fireEvent("mouseup", this);
13709 * Ext JS Library 1.1.1
13710 * Copyright(c) 2006-2007, Ext JS, LLC.
13712 * Originally Released Under LGPL - original licence link has changed is not relivant.
13715 * <script type="text/javascript">
13720 * @class Roo.KeyNav
13721 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13722 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13723 * way to implement custom navigation schemes for any UI component.</p>
13724 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13725 * pageUp, pageDown, del, home, end. Usage:</p>
13727 var nav = new Roo.KeyNav("my-element", {
13728 "left" : function(e){
13729 this.moveLeft(e.ctrlKey);
13731 "right" : function(e){
13732 this.moveRight(e.ctrlKey);
13734 "enter" : function(e){
13741 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13742 * @param {Object} config The config
13744 Roo.KeyNav = function(el, config){
13745 this.el = Roo.get(el);
13746 Roo.apply(this, config);
13747 if(!this.disabled){
13748 this.disabled = true;
13753 Roo.KeyNav.prototype = {
13755 * @cfg {Boolean} disabled
13756 * True to disable this KeyNav instance (defaults to false)
13760 * @cfg {String} defaultEventAction
13761 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13762 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13763 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13765 defaultEventAction: "stopEvent",
13767 * @cfg {Boolean} forceKeyDown
13768 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13769 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13770 * handle keydown instead of keypress.
13772 forceKeyDown : false,
13775 prepareEvent : function(e){
13776 var k = e.getKey();
13777 var h = this.keyToHandler[k];
13778 //if(h && this[h]){
13779 // e.stopPropagation();
13781 if(Roo.isSafari && h && k >= 37 && k <= 40){
13787 relay : function(e){
13788 var k = e.getKey();
13789 var h = this.keyToHandler[k];
13791 if(this.doRelay(e, this[h], h) !== true){
13792 e[this.defaultEventAction]();
13798 doRelay : function(e, h, hname){
13799 return h.call(this.scope || this, e);
13802 // possible handlers
13816 // quick lookup hash
13833 * Enable this KeyNav
13835 enable: function(){
13837 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13838 // the EventObject will normalize Safari automatically
13839 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13840 this.el.on("keydown", this.relay, this);
13842 this.el.on("keydown", this.prepareEvent, this);
13843 this.el.on("keypress", this.relay, this);
13845 this.disabled = false;
13850 * Disable this KeyNav
13852 disable: function(){
13853 if(!this.disabled){
13854 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13855 this.el.un("keydown", this.relay);
13857 this.el.un("keydown", this.prepareEvent);
13858 this.el.un("keypress", this.relay);
13860 this.disabled = true;
13865 * Ext JS Library 1.1.1
13866 * Copyright(c) 2006-2007, Ext JS, LLC.
13868 * Originally Released Under LGPL - original licence link has changed is not relivant.
13871 * <script type="text/javascript">
13876 * @class Roo.KeyMap
13877 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13878 * The constructor accepts the same config object as defined by {@link #addBinding}.
13879 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13880 * combination it will call the function with this signature (if the match is a multi-key
13881 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13882 * A KeyMap can also handle a string representation of keys.<br />
13885 // map one key by key code
13886 var map = new Roo.KeyMap("my-element", {
13887 key: 13, // or Roo.EventObject.ENTER
13892 // map multiple keys to one action by string
13893 var map = new Roo.KeyMap("my-element", {
13899 // map multiple keys to multiple actions by strings and array of codes
13900 var map = new Roo.KeyMap("my-element", [
13903 fn: function(){ alert("Return was pressed"); }
13906 fn: function(){ alert('a, b or c was pressed'); }
13911 fn: function(){ alert('Control + shift + tab was pressed.'); }
13915 * <b>Note: A KeyMap starts enabled</b>
13917 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13918 * @param {Object} config The config (see {@link #addBinding})
13919 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13921 Roo.KeyMap = function(el, config, eventName){
13922 this.el = Roo.get(el);
13923 this.eventName = eventName || "keydown";
13924 this.bindings = [];
13926 this.addBinding(config);
13931 Roo.KeyMap.prototype = {
13933 * True to stop the event from bubbling and prevent the default browser action if the
13934 * key was handled by the KeyMap (defaults to false)
13940 * Add a new binding to this KeyMap. The following config object properties are supported:
13942 Property Type Description
13943 ---------- --------------- ----------------------------------------------------------------------
13944 key String/Array A single keycode or an array of keycodes to handle
13945 shift Boolean True to handle key only when shift is pressed (defaults to false)
13946 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13947 alt Boolean True to handle key only when alt is pressed (defaults to false)
13948 fn Function The function to call when KeyMap finds the expected key combination
13949 scope Object The scope of the callback function
13955 var map = new Roo.KeyMap(document, {
13956 key: Roo.EventObject.ENTER,
13961 //Add a new binding to the existing KeyMap later
13969 * @param {Object/Array} config A single KeyMap config or an array of configs
13971 addBinding : function(config){
13972 if(config instanceof Array){
13973 for(var i = 0, len = config.length; i < len; i++){
13974 this.addBinding(config[i]);
13978 var keyCode = config.key,
13979 shift = config.shift,
13980 ctrl = config.ctrl,
13983 scope = config.scope;
13984 if(typeof keyCode == "string"){
13986 var keyString = keyCode.toUpperCase();
13987 for(var j = 0, len = keyString.length; j < len; j++){
13988 ks.push(keyString.charCodeAt(j));
13992 var keyArray = keyCode instanceof Array;
13993 var handler = function(e){
13994 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13995 var k = e.getKey();
13997 for(var i = 0, len = keyCode.length; i < len; i++){
13998 if(keyCode[i] == k){
13999 if(this.stopEvent){
14002 fn.call(scope || window, k, e);
14008 if(this.stopEvent){
14011 fn.call(scope || window, k, e);
14016 this.bindings.push(handler);
14020 * Shorthand for adding a single key listener
14021 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14022 * following options:
14023 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14024 * @param {Function} fn The function to call
14025 * @param {Object} scope (optional) The scope of the function
14027 on : function(key, fn, scope){
14028 var keyCode, shift, ctrl, alt;
14029 if(typeof key == "object" && !(key instanceof Array)){
14048 handleKeyDown : function(e){
14049 if(this.enabled){ //just in case
14050 var b = this.bindings;
14051 for(var i = 0, len = b.length; i < len; i++){
14052 b[i].call(this, e);
14058 * Returns true if this KeyMap is enabled
14059 * @return {Boolean}
14061 isEnabled : function(){
14062 return this.enabled;
14066 * Enables this KeyMap
14068 enable: function(){
14070 this.el.on(this.eventName, this.handleKeyDown, this);
14071 this.enabled = true;
14076 * Disable this KeyMap
14078 disable: function(){
14080 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14081 this.enabled = false;
14086 * Ext JS Library 1.1.1
14087 * Copyright(c) 2006-2007, Ext JS, LLC.
14089 * Originally Released Under LGPL - original licence link has changed is not relivant.
14092 * <script type="text/javascript">
14097 * @class Roo.util.TextMetrics
14098 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14099 * wide, in pixels, a given block of text will be.
14102 Roo.util.TextMetrics = function(){
14106 * Measures the size of the specified text
14107 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14108 * that can affect the size of the rendered text
14109 * @param {String} text The text to measure
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 {Object} An object containing the text's size {width: (width), height: (height)}
14114 measure : function(el, text, fixedWidth){
14116 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14119 shared.setFixedWidth(fixedWidth || 'auto');
14120 return shared.getSize(text);
14124 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14125 * the overhead of multiple calls to initialize the style properties on each measurement.
14126 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14127 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14128 * in order to accurately measure the text height
14129 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14131 createInstance : function(el, fixedWidth){
14132 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14139 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14140 var ml = new Roo.Element(document.createElement('div'));
14141 document.body.appendChild(ml.dom);
14142 ml.position('absolute');
14143 ml.setLeftTop(-1000, -1000);
14147 ml.setWidth(fixedWidth);
14152 * Returns the size of the specified text based on the internal element's style and width properties
14153 * @memberOf Roo.util.TextMetrics.Instance#
14154 * @param {String} text The text to measure
14155 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14157 getSize : function(text){
14159 var s = ml.getSize();
14165 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14166 * that can affect the size of the rendered text
14167 * @memberOf Roo.util.TextMetrics.Instance#
14168 * @param {String/HTMLElement} el The element, dom node or id
14170 bind : function(el){
14172 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14177 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14178 * to set a fixed width in order to accurately measure the text height.
14179 * @memberOf Roo.util.TextMetrics.Instance#
14180 * @param {Number} width The width to set on the element
14182 setFixedWidth : function(width){
14183 ml.setWidth(width);
14187 * Returns the measured width of the specified text
14188 * @memberOf Roo.util.TextMetrics.Instance#
14189 * @param {String} text The text to measure
14190 * @return {Number} width The width in pixels
14192 getWidth : function(text){
14193 ml.dom.style.width = 'auto';
14194 return this.getSize(text).width;
14198 * Returns the measured height of the specified text. For multiline text, be sure to call
14199 * {@link #setFixedWidth} if necessary.
14200 * @memberOf Roo.util.TextMetrics.Instance#
14201 * @param {String} text The text to measure
14202 * @return {Number} height The height in pixels
14204 getHeight : function(text){
14205 return this.getSize(text).height;
14209 instance.bind(bindTo);
14214 // backwards compat
14215 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14217 * Ext JS Library 1.1.1
14218 * Copyright(c) 2006-2007, Ext JS, LLC.
14220 * Originally Released Under LGPL - original licence link has changed is not relivant.
14223 * <script type="text/javascript">
14227 * @class Roo.state.Provider
14228 * Abstract base class for state provider implementations. This class provides methods
14229 * for encoding and decoding <b>typed</b> variables including dates and defines the
14230 * Provider interface.
14232 Roo.state.Provider = function(){
14234 * @event statechange
14235 * Fires when a state change occurs.
14236 * @param {Provider} this This state provider
14237 * @param {String} key The state key which was changed
14238 * @param {String} value The encoded value for the state
14241 "statechange": true
14244 Roo.state.Provider.superclass.constructor.call(this);
14246 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14248 * Returns the current value for a key
14249 * @param {String} name The key name
14250 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14251 * @return {Mixed} The state data
14253 get : function(name, defaultValue){
14254 return typeof this.state[name] == "undefined" ?
14255 defaultValue : this.state[name];
14259 * Clears a value from the state
14260 * @param {String} name The key name
14262 clear : function(name){
14263 delete this.state[name];
14264 this.fireEvent("statechange", this, name, null);
14268 * Sets the value for a key
14269 * @param {String} name The key name
14270 * @param {Mixed} value The value to set
14272 set : function(name, value){
14273 this.state[name] = value;
14274 this.fireEvent("statechange", this, name, value);
14278 * Decodes a string previously encoded with {@link #encodeValue}.
14279 * @param {String} value The value to decode
14280 * @return {Mixed} The decoded value
14282 decodeValue : function(cookie){
14283 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14284 var matches = re.exec(unescape(cookie));
14285 if(!matches || !matches[1]) return; // non state cookie
14286 var type = matches[1];
14287 var v = matches[2];
14290 return parseFloat(v);
14292 return new Date(Date.parse(v));
14297 var values = v.split("^");
14298 for(var i = 0, len = values.length; i < len; i++){
14299 all.push(this.decodeValue(values[i]));
14304 var values = v.split("^");
14305 for(var i = 0, len = values.length; i < len; i++){
14306 var kv = values[i].split("=");
14307 all[kv[0]] = this.decodeValue(kv[1]);
14316 * Encodes a value including type information. Decode with {@link #decodeValue}.
14317 * @param {Mixed} value The value to encode
14318 * @return {String} The encoded value
14320 encodeValue : function(v){
14322 if(typeof v == "number"){
14324 }else if(typeof v == "boolean"){
14325 enc = "b:" + (v ? "1" : "0");
14326 }else if(v instanceof Date){
14327 enc = "d:" + v.toGMTString();
14328 }else if(v instanceof Array){
14330 for(var i = 0, len = v.length; i < len; i++){
14331 flat += this.encodeValue(v[i]);
14332 if(i != len-1) flat += "^";
14335 }else if(typeof v == "object"){
14338 if(typeof v[key] != "function"){
14339 flat += key + "=" + this.encodeValue(v[key]) + "^";
14342 enc = "o:" + flat.substring(0, flat.length-1);
14346 return escape(enc);
14352 * Ext JS Library 1.1.1
14353 * Copyright(c) 2006-2007, Ext JS, LLC.
14355 * Originally Released Under LGPL - original licence link has changed is not relivant.
14358 * <script type="text/javascript">
14361 * @class Roo.state.Manager
14362 * This is the global state manager. By default all components that are "state aware" check this class
14363 * for state information if you don't pass them a custom state provider. In order for this class
14364 * to be useful, it must be initialized with a provider when your application initializes.
14366 // in your initialization function
14368 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14370 // supposed you have a {@link Roo.BorderLayout}
14371 var layout = new Roo.BorderLayout(...);
14372 layout.restoreState();
14373 // or a {Roo.BasicDialog}
14374 var dialog = new Roo.BasicDialog(...);
14375 dialog.restoreState();
14379 Roo.state.Manager = function(){
14380 var provider = new Roo.state.Provider();
14384 * Configures the default state provider for your application
14385 * @param {Provider} stateProvider The state provider to set
14387 setProvider : function(stateProvider){
14388 provider = stateProvider;
14392 * Returns the current value for a key
14393 * @param {String} name The key name
14394 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14395 * @return {Mixed} The state data
14397 get : function(key, defaultValue){
14398 return provider.get(key, defaultValue);
14402 * Sets the value for a key
14403 * @param {String} name The key name
14404 * @param {Mixed} value The state data
14406 set : function(key, value){
14407 provider.set(key, value);
14411 * Clears a value from the state
14412 * @param {String} name The key name
14414 clear : function(key){
14415 provider.clear(key);
14419 * Gets the currently configured state provider
14420 * @return {Provider} The state provider
14422 getProvider : function(){
14429 * Ext JS Library 1.1.1
14430 * Copyright(c) 2006-2007, Ext JS, LLC.
14432 * Originally Released Under LGPL - original licence link has changed is not relivant.
14435 * <script type="text/javascript">
14438 * @class Roo.state.CookieProvider
14439 * @extends Roo.state.Provider
14440 * The default Provider implementation which saves state via cookies.
14443 var cp = new Roo.state.CookieProvider({
14445 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14446 domain: "roojs.com"
14448 Roo.state.Manager.setProvider(cp);
14450 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14451 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14452 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14453 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14454 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14455 * domain the page is running on including the 'www' like 'www.roojs.com')
14456 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14458 * Create a new CookieProvider
14459 * @param {Object} config The configuration object
14461 Roo.state.CookieProvider = function(config){
14462 Roo.state.CookieProvider.superclass.constructor.call(this);
14464 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14465 this.domain = null;
14466 this.secure = false;
14467 Roo.apply(this, config);
14468 this.state = this.readCookies();
14471 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14473 set : function(name, value){
14474 if(typeof value == "undefined" || value === null){
14478 this.setCookie(name, value);
14479 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14483 clear : function(name){
14484 this.clearCookie(name);
14485 Roo.state.CookieProvider.superclass.clear.call(this, name);
14489 readCookies : function(){
14491 var c = document.cookie + ";";
14492 var re = /\s?(.*?)=(.*?);/g;
14494 while((matches = re.exec(c)) != null){
14495 var name = matches[1];
14496 var value = matches[2];
14497 if(name && name.substring(0,3) == "ys-"){
14498 cookies[name.substr(3)] = this.decodeValue(value);
14505 setCookie : function(name, value){
14506 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14507 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14508 ((this.path == null) ? "" : ("; path=" + this.path)) +
14509 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14510 ((this.secure == true) ? "; secure" : "");
14514 clearCookie : function(name){
14515 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14516 ((this.path == null) ? "" : ("; path=" + this.path)) +
14517 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14518 ((this.secure == true) ? "; secure" : "");
14522 * Ext JS Library 1.1.1
14523 * Copyright(c) 2006-2007, Ext JS, LLC.
14525 * Originally Released Under LGPL - original licence link has changed is not relivant.
14528 * <script type="text/javascript">
14534 * These classes are derivatives of the similarly named classes in the YUI Library.
14535 * The original license:
14536 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14537 * Code licensed under the BSD License:
14538 * http://developer.yahoo.net/yui/license.txt
14543 var Event=Roo.EventManager;
14544 var Dom=Roo.lib.Dom;
14547 * @class Roo.dd.DragDrop
14548 * @extends Roo.util.Observable
14549 * Defines the interface and base operation of items that that can be
14550 * dragged or can be drop targets. It was designed to be extended, overriding
14551 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14552 * Up to three html elements can be associated with a DragDrop instance:
14554 * <li>linked element: the element that is passed into the constructor.
14555 * This is the element which defines the boundaries for interaction with
14556 * other DragDrop objects.</li>
14557 * <li>handle element(s): The drag operation only occurs if the element that
14558 * was clicked matches a handle element. By default this is the linked
14559 * element, but there are times that you will want only a portion of the
14560 * linked element to initiate the drag operation, and the setHandleElId()
14561 * method provides a way to define this.</li>
14562 * <li>drag element: this represents the element that would be moved along
14563 * with the cursor during a drag operation. By default, this is the linked
14564 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14565 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14568 * This class should not be instantiated until the onload event to ensure that
14569 * the associated elements are available.
14570 * The following would define a DragDrop obj that would interact with any
14571 * other DragDrop obj in the "group1" group:
14573 * dd = new Roo.dd.DragDrop("div1", "group1");
14575 * Since none of the event handlers have been implemented, nothing would
14576 * actually happen if you were to run the code above. Normally you would
14577 * override this class or one of the default implementations, but you can
14578 * also override the methods you want on an instance of the class...
14580 * dd.onDragDrop = function(e, id) {
14581 * alert("dd was dropped on " + id);
14585 * @param {String} id of the element that is linked to this instance
14586 * @param {String} sGroup the group of related DragDrop objects
14587 * @param {object} config an object containing configurable attributes
14588 * Valid properties for DragDrop:
14589 * padding, isTarget, maintainOffset, primaryButtonOnly
14591 Roo.dd.DragDrop = function(id, sGroup, config) {
14593 this.init(id, sGroup, config);
14598 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14601 * The id of the element associated with this object. This is what we
14602 * refer to as the "linked element" because the size and position of
14603 * this element is used to determine when the drag and drop objects have
14611 * Configuration attributes passed into the constructor
14618 * The id of the element that will be dragged. By default this is same
14619 * as the linked element , but could be changed to another element. Ex:
14621 * @property dragElId
14628 * the id of the element that initiates the drag operation. By default
14629 * this is the linked element, but could be changed to be a child of this
14630 * element. This lets us do things like only starting the drag when the
14631 * header element within the linked html element is clicked.
14632 * @property handleElId
14639 * An associative array of HTML tags that will be ignored if clicked.
14640 * @property invalidHandleTypes
14641 * @type {string: string}
14643 invalidHandleTypes: null,
14646 * An associative array of ids for elements that will be ignored if clicked
14647 * @property invalidHandleIds
14648 * @type {string: string}
14650 invalidHandleIds: null,
14653 * An indexted array of css class names for elements that will be ignored
14655 * @property invalidHandleClasses
14658 invalidHandleClasses: null,
14661 * The linked element's absolute X position at the time the drag was
14663 * @property startPageX
14670 * The linked element's absolute X position at the time the drag was
14672 * @property startPageY
14679 * The group defines a logical collection of DragDrop objects that are
14680 * related. Instances only get events when interacting with other
14681 * DragDrop object in the same group. This lets us define multiple
14682 * groups using a single DragDrop subclass if we want.
14684 * @type {string: string}
14689 * Individual drag/drop instances can be locked. This will prevent
14690 * onmousedown start drag.
14698 * Lock this instance
14701 lock: function() { this.locked = true; },
14704 * Unlock this instace
14707 unlock: function() { this.locked = false; },
14710 * By default, all insances can be a drop target. This can be disabled by
14711 * setting isTarget to false.
14718 * The padding configured for this drag and drop object for calculating
14719 * the drop zone intersection with this object.
14726 * Cached reference to the linked element
14727 * @property _domRef
14733 * Internal typeof flag
14734 * @property __ygDragDrop
14737 __ygDragDrop: true,
14740 * Set to true when horizontal contraints are applied
14741 * @property constrainX
14748 * Set to true when vertical contraints are applied
14749 * @property constrainY
14756 * The left constraint
14764 * The right constraint
14772 * The up constraint
14781 * The down constraint
14789 * Maintain offsets when we resetconstraints. Set to true when you want
14790 * the position of the element relative to its parent to stay the same
14791 * when the page changes
14793 * @property maintainOffset
14796 maintainOffset: false,
14799 * Array of pixel locations the element will snap to if we specified a
14800 * horizontal graduation/interval. This array is generated automatically
14801 * when you define a tick interval.
14808 * Array of pixel locations the element will snap to if we specified a
14809 * vertical graduation/interval. This array is generated automatically
14810 * when you define a tick interval.
14817 * By default the drag and drop instance will only respond to the primary
14818 * button click (left button for a right-handed mouse). Set to true to
14819 * allow drag and drop to start with any mouse click that is propogated
14821 * @property primaryButtonOnly
14824 primaryButtonOnly: true,
14827 * The availabe property is false until the linked dom element is accessible.
14828 * @property available
14834 * By default, drags can only be initiated if the mousedown occurs in the
14835 * region the linked element is. This is done in part to work around a
14836 * bug in some browsers that mis-report the mousedown if the previous
14837 * mouseup happened outside of the window. This property is set to true
14838 * if outer handles are defined.
14840 * @property hasOuterHandles
14844 hasOuterHandles: false,
14847 * Code that executes immediately before the startDrag event
14848 * @method b4StartDrag
14851 b4StartDrag: function(x, y) { },
14854 * Abstract method called after a drag/drop object is clicked
14855 * and the drag or mousedown time thresholds have beeen met.
14856 * @method startDrag
14857 * @param {int} X click location
14858 * @param {int} Y click location
14860 startDrag: function(x, y) { /* override this */ },
14863 * Code that executes immediately before the onDrag event
14867 b4Drag: function(e) { },
14870 * Abstract method called during the onMouseMove event while dragging an
14873 * @param {Event} e the mousemove event
14875 onDrag: function(e) { /* override this */ },
14878 * Abstract method called when this element fist begins hovering over
14879 * another DragDrop obj
14880 * @method onDragEnter
14881 * @param {Event} e the mousemove event
14882 * @param {String|DragDrop[]} id In POINT mode, the element
14883 * id this is hovering over. In INTERSECT mode, an array of one or more
14884 * dragdrop items being hovered over.
14886 onDragEnter: function(e, id) { /* override this */ },
14889 * Code that executes immediately before the onDragOver event
14890 * @method b4DragOver
14893 b4DragOver: function(e) { },
14896 * Abstract method called when this element is hovering over another
14898 * @method onDragOver
14899 * @param {Event} e the mousemove event
14900 * @param {String|DragDrop[]} id In POINT mode, the element
14901 * id this is hovering over. In INTERSECT mode, an array of dd items
14902 * being hovered over.
14904 onDragOver: function(e, id) { /* override this */ },
14907 * Code that executes immediately before the onDragOut event
14908 * @method b4DragOut
14911 b4DragOut: function(e) { },
14914 * Abstract method called when we are no longer hovering over an element
14915 * @method onDragOut
14916 * @param {Event} e the mousemove event
14917 * @param {String|DragDrop[]} id In POINT mode, the element
14918 * id this was hovering over. In INTERSECT mode, an array of dd items
14919 * that the mouse is no longer over.
14921 onDragOut: function(e, id) { /* override this */ },
14924 * Code that executes immediately before the onDragDrop event
14925 * @method b4DragDrop
14928 b4DragDrop: function(e) { },
14931 * Abstract method called when this item is dropped on another DragDrop
14933 * @method onDragDrop
14934 * @param {Event} e the mouseup event
14935 * @param {String|DragDrop[]} id In POINT mode, the element
14936 * id this was dropped on. In INTERSECT mode, an array of dd items this
14939 onDragDrop: function(e, id) { /* override this */ },
14942 * Abstract method called when this item is dropped on an area with no
14944 * @method onInvalidDrop
14945 * @param {Event} e the mouseup event
14947 onInvalidDrop: function(e) { /* override this */ },
14950 * Code that executes immediately before the endDrag event
14951 * @method b4EndDrag
14954 b4EndDrag: function(e) { },
14957 * Fired when we are done dragging the object
14959 * @param {Event} e the mouseup event
14961 endDrag: function(e) { /* override this */ },
14964 * Code executed immediately before the onMouseDown event
14965 * @method b4MouseDown
14966 * @param {Event} e the mousedown event
14969 b4MouseDown: function(e) { },
14972 * Event handler that fires when a drag/drop obj gets a mousedown
14973 * @method onMouseDown
14974 * @param {Event} e the mousedown event
14976 onMouseDown: function(e) { /* override this */ },
14979 * Event handler that fires when a drag/drop obj gets a mouseup
14980 * @method onMouseUp
14981 * @param {Event} e the mouseup event
14983 onMouseUp: function(e) { /* override this */ },
14986 * Override the onAvailable method to do what is needed after the initial
14987 * position was determined.
14988 * @method onAvailable
14990 onAvailable: function () {
14994 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14997 defaultPadding : {left:0, right:0, top:0, bottom:0},
15000 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15004 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15005 { dragElId: "existingProxyDiv" });
15006 dd.startDrag = function(){
15007 this.constrainTo("parent-id");
15010 * Or you can initalize it using the {@link Roo.Element} object:
15012 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15013 startDrag : function(){
15014 this.constrainTo("parent-id");
15018 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15019 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15020 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15021 * an object containing the sides to pad. For example: {right:10, bottom:10}
15022 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15024 constrainTo : function(constrainTo, pad, inContent){
15025 if(typeof pad == "number"){
15026 pad = {left: pad, right:pad, top:pad, bottom:pad};
15028 pad = pad || this.defaultPadding;
15029 var b = Roo.get(this.getEl()).getBox();
15030 var ce = Roo.get(constrainTo);
15031 var s = ce.getScroll();
15032 var c, cd = ce.dom;
15033 if(cd == document.body){
15034 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15037 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15041 var topSpace = b.y - c.y;
15042 var leftSpace = b.x - c.x;
15044 this.resetConstraints();
15045 this.setXConstraint(leftSpace - (pad.left||0), // left
15046 c.width - leftSpace - b.width - (pad.right||0) //right
15048 this.setYConstraint(topSpace - (pad.top||0), //top
15049 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15054 * Returns a reference to the linked element
15056 * @return {HTMLElement} the html element
15058 getEl: function() {
15059 if (!this._domRef) {
15060 this._domRef = Roo.getDom(this.id);
15063 return this._domRef;
15067 * Returns a reference to the actual element to drag. By default this is
15068 * the same as the html element, but it can be assigned to another
15069 * element. An example of this can be found in Roo.dd.DDProxy
15070 * @method getDragEl
15071 * @return {HTMLElement} the html element
15073 getDragEl: function() {
15074 return Roo.getDom(this.dragElId);
15078 * Sets up the DragDrop object. Must be called in the constructor of any
15079 * Roo.dd.DragDrop subclass
15081 * @param id the id of the linked element
15082 * @param {String} sGroup the group of related items
15083 * @param {object} config configuration attributes
15085 init: function(id, sGroup, config) {
15086 this.initTarget(id, sGroup, config);
15087 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15088 // Event.on(this.id, "selectstart", Event.preventDefault);
15092 * Initializes Targeting functionality only... the object does not
15093 * get a mousedown handler.
15094 * @method initTarget
15095 * @param id the id of the linked element
15096 * @param {String} sGroup the group of related items
15097 * @param {object} config configuration attributes
15099 initTarget: function(id, sGroup, config) {
15101 // configuration attributes
15102 this.config = config || {};
15104 // create a local reference to the drag and drop manager
15105 this.DDM = Roo.dd.DDM;
15106 // initialize the groups array
15109 // assume that we have an element reference instead of an id if the
15110 // parameter is not a string
15111 if (typeof id !== "string") {
15118 // add to an interaction group
15119 this.addToGroup((sGroup) ? sGroup : "default");
15121 // We don't want to register this as the handle with the manager
15122 // so we just set the id rather than calling the setter.
15123 this.handleElId = id;
15125 // the linked element is the element that gets dragged by default
15126 this.setDragElId(id);
15128 // by default, clicked anchors will not start drag operations.
15129 this.invalidHandleTypes = { A: "A" };
15130 this.invalidHandleIds = {};
15131 this.invalidHandleClasses = [];
15133 this.applyConfig();
15135 this.handleOnAvailable();
15139 * Applies the configuration parameters that were passed into the constructor.
15140 * This is supposed to happen at each level through the inheritance chain. So
15141 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15142 * DragDrop in order to get all of the parameters that are available in
15144 * @method applyConfig
15146 applyConfig: function() {
15148 // configurable properties:
15149 // padding, isTarget, maintainOffset, primaryButtonOnly
15150 this.padding = this.config.padding || [0, 0, 0, 0];
15151 this.isTarget = (this.config.isTarget !== false);
15152 this.maintainOffset = (this.config.maintainOffset);
15153 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15158 * Executed when the linked element is available
15159 * @method handleOnAvailable
15162 handleOnAvailable: function() {
15163 this.available = true;
15164 this.resetConstraints();
15165 this.onAvailable();
15169 * Configures the padding for the target zone in px. Effectively expands
15170 * (or reduces) the virtual object size for targeting calculations.
15171 * Supports css-style shorthand; if only one parameter is passed, all sides
15172 * will have that padding, and if only two are passed, the top and bottom
15173 * will have the first param, the left and right the second.
15174 * @method setPadding
15175 * @param {int} iTop Top pad
15176 * @param {int} iRight Right pad
15177 * @param {int} iBot Bot pad
15178 * @param {int} iLeft Left pad
15180 setPadding: function(iTop, iRight, iBot, iLeft) {
15181 // this.padding = [iLeft, iRight, iTop, iBot];
15182 if (!iRight && 0 !== iRight) {
15183 this.padding = [iTop, iTop, iTop, iTop];
15184 } else if (!iBot && 0 !== iBot) {
15185 this.padding = [iTop, iRight, iTop, iRight];
15187 this.padding = [iTop, iRight, iBot, iLeft];
15192 * Stores the initial placement of the linked element.
15193 * @method setInitialPosition
15194 * @param {int} diffX the X offset, default 0
15195 * @param {int} diffY the Y offset, default 0
15197 setInitPosition: function(diffX, diffY) {
15198 var el = this.getEl();
15200 if (!this.DDM.verifyEl(el)) {
15204 var dx = diffX || 0;
15205 var dy = diffY || 0;
15207 var p = Dom.getXY( el );
15209 this.initPageX = p[0] - dx;
15210 this.initPageY = p[1] - dy;
15212 this.lastPageX = p[0];
15213 this.lastPageY = p[1];
15216 this.setStartPosition(p);
15220 * Sets the start position of the element. This is set when the obj
15221 * is initialized, the reset when a drag is started.
15222 * @method setStartPosition
15223 * @param pos current position (from previous lookup)
15226 setStartPosition: function(pos) {
15227 var p = pos || Dom.getXY( this.getEl() );
15228 this.deltaSetXY = null;
15230 this.startPageX = p[0];
15231 this.startPageY = p[1];
15235 * Add this instance to a group of related drag/drop objects. All
15236 * instances belong to at least one group, and can belong to as many
15237 * groups as needed.
15238 * @method addToGroup
15239 * @param sGroup {string} the name of the group
15241 addToGroup: function(sGroup) {
15242 this.groups[sGroup] = true;
15243 this.DDM.regDragDrop(this, sGroup);
15247 * Remove's this instance from the supplied interaction group
15248 * @method removeFromGroup
15249 * @param {string} sGroup The group to drop
15251 removeFromGroup: function(sGroup) {
15252 if (this.groups[sGroup]) {
15253 delete this.groups[sGroup];
15256 this.DDM.removeDDFromGroup(this, sGroup);
15260 * Allows you to specify that an element other than the linked element
15261 * will be moved with the cursor during a drag
15262 * @method setDragElId
15263 * @param id {string} the id of the element that will be used to initiate the drag
15265 setDragElId: function(id) {
15266 this.dragElId = id;
15270 * Allows you to specify a child of the linked element that should be
15271 * used to initiate the drag operation. An example of this would be if
15272 * you have a content div with text and links. Clicking anywhere in the
15273 * content area would normally start the drag operation. Use this method
15274 * to specify that an element inside of the content div is the element
15275 * that starts the drag operation.
15276 * @method setHandleElId
15277 * @param id {string} the id of the element that will be used to
15278 * initiate the drag.
15280 setHandleElId: function(id) {
15281 if (typeof id !== "string") {
15284 this.handleElId = id;
15285 this.DDM.regHandle(this.id, id);
15289 * Allows you to set an element outside of the linked element as a drag
15291 * @method setOuterHandleElId
15292 * @param id the id of the element that will be used to initiate the drag
15294 setOuterHandleElId: function(id) {
15295 if (typeof id !== "string") {
15298 Event.on(id, "mousedown",
15299 this.handleMouseDown, this);
15300 this.setHandleElId(id);
15302 this.hasOuterHandles = true;
15306 * Remove all drag and drop hooks for this element
15309 unreg: function() {
15310 Event.un(this.id, "mousedown",
15311 this.handleMouseDown);
15312 this._domRef = null;
15313 this.DDM._remove(this);
15316 destroy : function(){
15321 * Returns true if this instance is locked, or the drag drop mgr is locked
15322 * (meaning that all drag/drop is disabled on the page.)
15324 * @return {boolean} true if this obj or all drag/drop is locked, else
15327 isLocked: function() {
15328 return (this.DDM.isLocked() || this.locked);
15332 * Fired when this object is clicked
15333 * @method handleMouseDown
15335 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15338 handleMouseDown: function(e, oDD){
15339 if (this.primaryButtonOnly && e.button != 0) {
15343 if (this.isLocked()) {
15347 this.DDM.refreshCache(this.groups);
15349 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15350 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15352 if (this.clickValidator(e)) {
15354 // set the initial element position
15355 this.setStartPosition();
15358 this.b4MouseDown(e);
15359 this.onMouseDown(e);
15361 this.DDM.handleMouseDown(e, this);
15363 this.DDM.stopEvent(e);
15371 clickValidator: function(e) {
15372 var target = e.getTarget();
15373 return ( this.isValidHandleChild(target) &&
15374 (this.id == this.handleElId ||
15375 this.DDM.handleWasClicked(target, this.id)) );
15379 * Allows you to specify a tag name that should not start a drag operation
15380 * when clicked. This is designed to facilitate embedding links within a
15381 * drag handle that do something other than start the drag.
15382 * @method addInvalidHandleType
15383 * @param {string} tagName the type of element to exclude
15385 addInvalidHandleType: function(tagName) {
15386 var type = tagName.toUpperCase();
15387 this.invalidHandleTypes[type] = type;
15391 * Lets you to specify an element id for a child of a drag handle
15392 * that should not initiate a drag
15393 * @method addInvalidHandleId
15394 * @param {string} id the element id of the element you wish to ignore
15396 addInvalidHandleId: function(id) {
15397 if (typeof id !== "string") {
15400 this.invalidHandleIds[id] = id;
15404 * Lets you specify a css class of elements that will not initiate a drag
15405 * @method addInvalidHandleClass
15406 * @param {string} cssClass the class of the elements you wish to ignore
15408 addInvalidHandleClass: function(cssClass) {
15409 this.invalidHandleClasses.push(cssClass);
15413 * Unsets an excluded tag name set by addInvalidHandleType
15414 * @method removeInvalidHandleType
15415 * @param {string} tagName the type of element to unexclude
15417 removeInvalidHandleType: function(tagName) {
15418 var type = tagName.toUpperCase();
15419 // this.invalidHandleTypes[type] = null;
15420 delete this.invalidHandleTypes[type];
15424 * Unsets an invalid handle id
15425 * @method removeInvalidHandleId
15426 * @param {string} id the id of the element to re-enable
15428 removeInvalidHandleId: function(id) {
15429 if (typeof id !== "string") {
15432 delete this.invalidHandleIds[id];
15436 * Unsets an invalid css class
15437 * @method removeInvalidHandleClass
15438 * @param {string} cssClass the class of the element(s) you wish to
15441 removeInvalidHandleClass: function(cssClass) {
15442 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15443 if (this.invalidHandleClasses[i] == cssClass) {
15444 delete this.invalidHandleClasses[i];
15450 * Checks the tag exclusion list to see if this click should be ignored
15451 * @method isValidHandleChild
15452 * @param {HTMLElement} node the HTMLElement to evaluate
15453 * @return {boolean} true if this is a valid tag type, false if not
15455 isValidHandleChild: function(node) {
15458 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15461 nodeName = node.nodeName.toUpperCase();
15463 nodeName = node.nodeName;
15465 valid = valid && !this.invalidHandleTypes[nodeName];
15466 valid = valid && !this.invalidHandleIds[node.id];
15468 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15469 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15478 * Create the array of horizontal tick marks if an interval was specified
15479 * in setXConstraint().
15480 * @method setXTicks
15483 setXTicks: function(iStartX, iTickSize) {
15485 this.xTickSize = iTickSize;
15489 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15491 this.xTicks[this.xTicks.length] = i;
15496 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15498 this.xTicks[this.xTicks.length] = i;
15503 this.xTicks.sort(this.DDM.numericSort) ;
15507 * Create the array of vertical tick marks if an interval was specified in
15508 * setYConstraint().
15509 * @method setYTicks
15512 setYTicks: function(iStartY, iTickSize) {
15514 this.yTickSize = iTickSize;
15518 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15520 this.yTicks[this.yTicks.length] = i;
15525 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15527 this.yTicks[this.yTicks.length] = i;
15532 this.yTicks.sort(this.DDM.numericSort) ;
15536 * By default, the element can be dragged any place on the screen. Use
15537 * this method to limit the horizontal travel of the element. Pass in
15538 * 0,0 for the parameters if you want to lock the drag to the y axis.
15539 * @method setXConstraint
15540 * @param {int} iLeft the number of pixels the element can move to the left
15541 * @param {int} iRight the number of pixels the element can move to the
15543 * @param {int} iTickSize optional parameter for specifying that the
15545 * should move iTickSize pixels at a time.
15547 setXConstraint: function(iLeft, iRight, iTickSize) {
15548 this.leftConstraint = iLeft;
15549 this.rightConstraint = iRight;
15551 this.minX = this.initPageX - iLeft;
15552 this.maxX = this.initPageX + iRight;
15553 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15555 this.constrainX = true;
15559 * Clears any constraints applied to this instance. Also clears ticks
15560 * since they can't exist independent of a constraint at this time.
15561 * @method clearConstraints
15563 clearConstraints: function() {
15564 this.constrainX = false;
15565 this.constrainY = false;
15570 * Clears any tick interval defined for this instance
15571 * @method clearTicks
15573 clearTicks: function() {
15574 this.xTicks = null;
15575 this.yTicks = null;
15576 this.xTickSize = 0;
15577 this.yTickSize = 0;
15581 * By default, the element can be dragged any place on the screen. Set
15582 * this to limit the vertical travel of the element. Pass in 0,0 for the
15583 * parameters if you want to lock the drag to the x axis.
15584 * @method setYConstraint
15585 * @param {int} iUp the number of pixels the element can move up
15586 * @param {int} iDown the number of pixels the element can move down
15587 * @param {int} iTickSize optional parameter for specifying that the
15588 * element should move iTickSize pixels at a time.
15590 setYConstraint: function(iUp, iDown, iTickSize) {
15591 this.topConstraint = iUp;
15592 this.bottomConstraint = iDown;
15594 this.minY = this.initPageY - iUp;
15595 this.maxY = this.initPageY + iDown;
15596 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15598 this.constrainY = true;
15603 * resetConstraints must be called if you manually reposition a dd element.
15604 * @method resetConstraints
15605 * @param {boolean} maintainOffset
15607 resetConstraints: function() {
15610 // Maintain offsets if necessary
15611 if (this.initPageX || this.initPageX === 0) {
15612 // figure out how much this thing has moved
15613 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15614 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15616 this.setInitPosition(dx, dy);
15618 // This is the first time we have detected the element's position
15620 this.setInitPosition();
15623 if (this.constrainX) {
15624 this.setXConstraint( this.leftConstraint,
15625 this.rightConstraint,
15629 if (this.constrainY) {
15630 this.setYConstraint( this.topConstraint,
15631 this.bottomConstraint,
15637 * Normally the drag element is moved pixel by pixel, but we can specify
15638 * that it move a number of pixels at a time. This method resolves the
15639 * location when we have it set up like this.
15641 * @param {int} val where we want to place the object
15642 * @param {int[]} tickArray sorted array of valid points
15643 * @return {int} the closest tick
15646 getTick: function(val, tickArray) {
15649 // If tick interval is not defined, it is effectively 1 pixel,
15650 // so we return the value passed to us.
15652 } else if (tickArray[0] >= val) {
15653 // The value is lower than the first tick, so we return the first
15655 return tickArray[0];
15657 for (var i=0, len=tickArray.length; i<len; ++i) {
15659 if (tickArray[next] && tickArray[next] >= val) {
15660 var diff1 = val - tickArray[i];
15661 var diff2 = tickArray[next] - val;
15662 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15666 // The value is larger than the last tick, so we return the last
15668 return tickArray[tickArray.length - 1];
15675 * @return {string} string representation of the dd obj
15677 toString: function() {
15678 return ("DragDrop " + this.id);
15686 * Ext JS Library 1.1.1
15687 * Copyright(c) 2006-2007, Ext JS, LLC.
15689 * Originally Released Under LGPL - original licence link has changed is not relivant.
15692 * <script type="text/javascript">
15697 * The drag and drop utility provides a framework for building drag and drop
15698 * applications. In addition to enabling drag and drop for specific elements,
15699 * the drag and drop elements are tracked by the manager class, and the
15700 * interactions between the various elements are tracked during the drag and
15701 * the implementing code is notified about these important moments.
15704 // Only load the library once. Rewriting the manager class would orphan
15705 // existing drag and drop instances.
15706 if (!Roo.dd.DragDropMgr) {
15709 * @class Roo.dd.DragDropMgr
15710 * DragDropMgr is a singleton that tracks the element interaction for
15711 * all DragDrop items in the window. Generally, you will not call
15712 * this class directly, but it does have helper methods that could
15713 * be useful in your DragDrop implementations.
15716 Roo.dd.DragDropMgr = function() {
15718 var Event = Roo.EventManager;
15723 * Two dimensional Array of registered DragDrop objects. The first
15724 * dimension is the DragDrop item group, the second the DragDrop
15727 * @type {string: string}
15734 * Array of element ids defined as drag handles. Used to determine
15735 * if the element that generated the mousedown event is actually the
15736 * handle and not the html element itself.
15737 * @property handleIds
15738 * @type {string: string}
15745 * the DragDrop object that is currently being dragged
15746 * @property dragCurrent
15754 * the DragDrop object(s) that are being hovered over
15755 * @property dragOvers
15763 * the X distance between the cursor and the object being dragged
15772 * the Y distance between the cursor and the object being dragged
15781 * Flag to determine if we should prevent the default behavior of the
15782 * events we define. By default this is true, but this can be set to
15783 * false if you need the default behavior (not recommended)
15784 * @property preventDefault
15788 preventDefault: true,
15791 * Flag to determine if we should stop the propagation of the events
15792 * we generate. This is true by default but you may want to set it to
15793 * false if the html element contains other features that require the
15795 * @property stopPropagation
15799 stopPropagation: true,
15802 * Internal flag that is set to true when drag and drop has been
15804 * @property initialized
15811 * All drag and drop can be disabled.
15819 * Called the first time an element is registered.
15825 this.initialized = true;
15829 * In point mode, drag and drop interaction is defined by the
15830 * location of the cursor during the drag/drop
15838 * In intersect mode, drag and drop interactio nis defined by the
15839 * overlap of two or more drag and drop objects.
15840 * @property INTERSECT
15847 * The current drag and drop mode. Default: POINT
15855 * Runs method on all drag and drop objects
15856 * @method _execOnAll
15860 _execOnAll: function(sMethod, args) {
15861 for (var i in this.ids) {
15862 for (var j in this.ids[i]) {
15863 var oDD = this.ids[i][j];
15864 if (! this.isTypeOfDD(oDD)) {
15867 oDD[sMethod].apply(oDD, args);
15873 * Drag and drop initialization. Sets up the global event handlers
15878 _onLoad: function() {
15883 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15884 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15885 Event.on(window, "unload", this._onUnload, this, true);
15886 Event.on(window, "resize", this._onResize, this, true);
15887 // Event.on(window, "mouseout", this._test);
15892 * Reset constraints on all drag and drop objs
15893 * @method _onResize
15897 _onResize: function(e) {
15898 this._execOnAll("resetConstraints", []);
15902 * Lock all drag and drop functionality
15906 lock: function() { this.locked = true; },
15909 * Unlock all drag and drop functionality
15913 unlock: function() { this.locked = false; },
15916 * Is drag and drop locked?
15918 * @return {boolean} True if drag and drop is locked, false otherwise.
15921 isLocked: function() { return this.locked; },
15924 * Location cache that is set for all drag drop objects when a drag is
15925 * initiated, cleared when the drag is finished.
15926 * @property locationCache
15933 * Set useCache to false if you want to force object the lookup of each
15934 * drag and drop linked element constantly during a drag.
15935 * @property useCache
15942 * The number of pixels that the mouse needs to move after the
15943 * mousedown before the drag is initiated. Default=3;
15944 * @property clickPixelThresh
15948 clickPixelThresh: 3,
15951 * The number of milliseconds after the mousedown event to initiate the
15952 * drag if we don't get a mouseup event. Default=1000
15953 * @property clickTimeThresh
15957 clickTimeThresh: 350,
15960 * Flag that indicates that either the drag pixel threshold or the
15961 * mousdown time threshold has been met
15962 * @property dragThreshMet
15967 dragThreshMet: false,
15970 * Timeout used for the click time threshold
15971 * @property clickTimeout
15976 clickTimeout: null,
15979 * The X position of the mousedown event stored for later use when a
15980 * drag threshold is met.
15989 * The Y position of the mousedown event stored for later use when a
15990 * drag threshold is met.
15999 * Each DragDrop instance must be registered with the DragDropMgr.
16000 * This is executed in DragDrop.init()
16001 * @method regDragDrop
16002 * @param {DragDrop} oDD the DragDrop object to register
16003 * @param {String} sGroup the name of the group this element belongs to
16006 regDragDrop: function(oDD, sGroup) {
16007 if (!this.initialized) { this.init(); }
16009 if (!this.ids[sGroup]) {
16010 this.ids[sGroup] = {};
16012 this.ids[sGroup][oDD.id] = oDD;
16016 * Removes the supplied dd instance from the supplied group. Executed
16017 * by DragDrop.removeFromGroup, so don't call this function directly.
16018 * @method removeDDFromGroup
16022 removeDDFromGroup: function(oDD, sGroup) {
16023 if (!this.ids[sGroup]) {
16024 this.ids[sGroup] = {};
16027 var obj = this.ids[sGroup];
16028 if (obj && obj[oDD.id]) {
16029 delete obj[oDD.id];
16034 * Unregisters a drag and drop item. This is executed in
16035 * DragDrop.unreg, use that method instead of calling this directly.
16040 _remove: function(oDD) {
16041 for (var g in oDD.groups) {
16042 if (g && this.ids[g][oDD.id]) {
16043 delete this.ids[g][oDD.id];
16046 delete this.handleIds[oDD.id];
16050 * Each DragDrop handle element must be registered. This is done
16051 * automatically when executing DragDrop.setHandleElId()
16052 * @method regHandle
16053 * @param {String} sDDId the DragDrop id this element is a handle for
16054 * @param {String} sHandleId the id of the element that is the drag
16058 regHandle: function(sDDId, sHandleId) {
16059 if (!this.handleIds[sDDId]) {
16060 this.handleIds[sDDId] = {};
16062 this.handleIds[sDDId][sHandleId] = sHandleId;
16066 * Utility function to determine if a given element has been
16067 * registered as a drag drop item.
16068 * @method isDragDrop
16069 * @param {String} id the element id to check
16070 * @return {boolean} true if this element is a DragDrop item,
16074 isDragDrop: function(id) {
16075 return ( this.getDDById(id) ) ? true : false;
16079 * Returns the drag and drop instances that are in all groups the
16080 * passed in instance belongs to.
16081 * @method getRelated
16082 * @param {DragDrop} p_oDD the obj to get related data for
16083 * @param {boolean} bTargetsOnly if true, only return targetable objs
16084 * @return {DragDrop[]} the related instances
16087 getRelated: function(p_oDD, bTargetsOnly) {
16089 for (var i in p_oDD.groups) {
16090 for (j in this.ids[i]) {
16091 var dd = this.ids[i][j];
16092 if (! this.isTypeOfDD(dd)) {
16095 if (!bTargetsOnly || dd.isTarget) {
16096 oDDs[oDDs.length] = dd;
16105 * Returns true if the specified dd target is a legal target for
16106 * the specifice drag obj
16107 * @method isLegalTarget
16108 * @param {DragDrop} the drag obj
16109 * @param {DragDrop} the target
16110 * @return {boolean} true if the target is a legal target for the
16114 isLegalTarget: function (oDD, oTargetDD) {
16115 var targets = this.getRelated(oDD, true);
16116 for (var i=0, len=targets.length;i<len;++i) {
16117 if (targets[i].id == oTargetDD.id) {
16126 * My goal is to be able to transparently determine if an object is
16127 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16128 * returns "object", oDD.constructor.toString() always returns
16129 * "DragDrop" and not the name of the subclass. So for now it just
16130 * evaluates a well-known variable in DragDrop.
16131 * @method isTypeOfDD
16132 * @param {Object} the object to evaluate
16133 * @return {boolean} true if typeof oDD = DragDrop
16136 isTypeOfDD: function (oDD) {
16137 return (oDD && oDD.__ygDragDrop);
16141 * Utility function to determine if a given element has been
16142 * registered as a drag drop handle for the given Drag Drop object.
16144 * @param {String} id the element id to check
16145 * @return {boolean} true if this element is a DragDrop handle, false
16149 isHandle: function(sDDId, sHandleId) {
16150 return ( this.handleIds[sDDId] &&
16151 this.handleIds[sDDId][sHandleId] );
16155 * Returns the DragDrop instance for a given id
16156 * @method getDDById
16157 * @param {String} id the id of the DragDrop object
16158 * @return {DragDrop} the drag drop object, null if it is not found
16161 getDDById: function(id) {
16162 for (var i in this.ids) {
16163 if (this.ids[i][id]) {
16164 return this.ids[i][id];
16171 * Fired after a registered DragDrop object gets the mousedown event.
16172 * Sets up the events required to track the object being dragged
16173 * @method handleMouseDown
16174 * @param {Event} e the event
16175 * @param oDD the DragDrop object being dragged
16179 handleMouseDown: function(e, oDD) {
16181 Roo.QuickTips.disable();
16183 this.currentTarget = e.getTarget();
16185 this.dragCurrent = oDD;
16187 var el = oDD.getEl();
16189 // track start position
16190 this.startX = e.getPageX();
16191 this.startY = e.getPageY();
16193 this.deltaX = this.startX - el.offsetLeft;
16194 this.deltaY = this.startY - el.offsetTop;
16196 this.dragThreshMet = false;
16198 this.clickTimeout = setTimeout(
16200 var DDM = Roo.dd.DDM;
16201 DDM.startDrag(DDM.startX, DDM.startY);
16203 this.clickTimeThresh );
16207 * Fired when either the drag pixel threshol or the mousedown hold
16208 * time threshold has been met.
16209 * @method startDrag
16210 * @param x {int} the X position of the original mousedown
16211 * @param y {int} the Y position of the original mousedown
16214 startDrag: function(x, y) {
16215 clearTimeout(this.clickTimeout);
16216 if (this.dragCurrent) {
16217 this.dragCurrent.b4StartDrag(x, y);
16218 this.dragCurrent.startDrag(x, y);
16220 this.dragThreshMet = true;
16224 * Internal function to handle the mouseup event. Will be invoked
16225 * from the context of the document.
16226 * @method handleMouseUp
16227 * @param {Event} e the event
16231 handleMouseUp: function(e) {
16234 Roo.QuickTips.enable();
16236 if (! this.dragCurrent) {
16240 clearTimeout(this.clickTimeout);
16242 if (this.dragThreshMet) {
16243 this.fireEvents(e, true);
16253 * Utility to stop event propagation and event default, if these
16254 * features are turned on.
16255 * @method stopEvent
16256 * @param {Event} e the event as returned by this.getEvent()
16259 stopEvent: function(e){
16260 if(this.stopPropagation) {
16261 e.stopPropagation();
16264 if (this.preventDefault) {
16265 e.preventDefault();
16270 * Internal function to clean up event handlers after the drag
16271 * operation is complete
16273 * @param {Event} e the event
16277 stopDrag: function(e) {
16278 // Fire the drag end event for the item that was dragged
16279 if (this.dragCurrent) {
16280 if (this.dragThreshMet) {
16281 this.dragCurrent.b4EndDrag(e);
16282 this.dragCurrent.endDrag(e);
16285 this.dragCurrent.onMouseUp(e);
16288 this.dragCurrent = null;
16289 this.dragOvers = {};
16293 * Internal function to handle the mousemove event. Will be invoked
16294 * from the context of the html element.
16296 * @TODO figure out what we can do about mouse events lost when the
16297 * user drags objects beyond the window boundary. Currently we can
16298 * detect this in internet explorer by verifying that the mouse is
16299 * down during the mousemove event. Firefox doesn't give us the
16300 * button state on the mousemove event.
16301 * @method handleMouseMove
16302 * @param {Event} e the event
16306 handleMouseMove: function(e) {
16307 if (! this.dragCurrent) {
16311 // var button = e.which || e.button;
16313 // check for IE mouseup outside of page boundary
16314 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16316 return this.handleMouseUp(e);
16319 if (!this.dragThreshMet) {
16320 var diffX = Math.abs(this.startX - e.getPageX());
16321 var diffY = Math.abs(this.startY - e.getPageY());
16322 if (diffX > this.clickPixelThresh ||
16323 diffY > this.clickPixelThresh) {
16324 this.startDrag(this.startX, this.startY);
16328 if (this.dragThreshMet) {
16329 this.dragCurrent.b4Drag(e);
16330 this.dragCurrent.onDrag(e);
16331 if(!this.dragCurrent.moveOnly){
16332 this.fireEvents(e, false);
16342 * Iterates over all of the DragDrop elements to find ones we are
16343 * hovering over or dropping on
16344 * @method fireEvents
16345 * @param {Event} e the event
16346 * @param {boolean} isDrop is this a drop op or a mouseover op?
16350 fireEvents: function(e, isDrop) {
16351 var dc = this.dragCurrent;
16353 // If the user did the mouse up outside of the window, we could
16354 // get here even though we have ended the drag.
16355 if (!dc || dc.isLocked()) {
16359 var pt = e.getPoint();
16361 // cache the previous dragOver array
16367 var enterEvts = [];
16369 // Check to see if the object(s) we were hovering over is no longer
16370 // being hovered over so we can fire the onDragOut event
16371 for (var i in this.dragOvers) {
16373 var ddo = this.dragOvers[i];
16375 if (! this.isTypeOfDD(ddo)) {
16379 if (! this.isOverTarget(pt, ddo, this.mode)) {
16380 outEvts.push( ddo );
16383 oldOvers[i] = true;
16384 delete this.dragOvers[i];
16387 for (var sGroup in dc.groups) {
16389 if ("string" != typeof sGroup) {
16393 for (i in this.ids[sGroup]) {
16394 var oDD = this.ids[sGroup][i];
16395 if (! this.isTypeOfDD(oDD)) {
16399 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16400 if (this.isOverTarget(pt, oDD, this.mode)) {
16401 // look for drop interactions
16403 dropEvts.push( oDD );
16404 // look for drag enter and drag over interactions
16407 // initial drag over: dragEnter fires
16408 if (!oldOvers[oDD.id]) {
16409 enterEvts.push( oDD );
16410 // subsequent drag overs: dragOver fires
16412 overEvts.push( oDD );
16415 this.dragOvers[oDD.id] = oDD;
16423 if (outEvts.length) {
16424 dc.b4DragOut(e, outEvts);
16425 dc.onDragOut(e, outEvts);
16428 if (enterEvts.length) {
16429 dc.onDragEnter(e, enterEvts);
16432 if (overEvts.length) {
16433 dc.b4DragOver(e, overEvts);
16434 dc.onDragOver(e, overEvts);
16437 if (dropEvts.length) {
16438 dc.b4DragDrop(e, dropEvts);
16439 dc.onDragDrop(e, dropEvts);
16443 // fire dragout events
16445 for (i=0, len=outEvts.length; i<len; ++i) {
16446 dc.b4DragOut(e, outEvts[i].id);
16447 dc.onDragOut(e, outEvts[i].id);
16450 // fire enter events
16451 for (i=0,len=enterEvts.length; i<len; ++i) {
16452 // dc.b4DragEnter(e, oDD.id);
16453 dc.onDragEnter(e, enterEvts[i].id);
16456 // fire over events
16457 for (i=0,len=overEvts.length; i<len; ++i) {
16458 dc.b4DragOver(e, overEvts[i].id);
16459 dc.onDragOver(e, overEvts[i].id);
16462 // fire drop events
16463 for (i=0, len=dropEvts.length; i<len; ++i) {
16464 dc.b4DragDrop(e, dropEvts[i].id);
16465 dc.onDragDrop(e, dropEvts[i].id);
16470 // notify about a drop that did not find a target
16471 if (isDrop && !dropEvts.length) {
16472 dc.onInvalidDrop(e);
16478 * Helper function for getting the best match from the list of drag
16479 * and drop objects returned by the drag and drop events when we are
16480 * in INTERSECT mode. It returns either the first object that the
16481 * cursor is over, or the object that has the greatest overlap with
16482 * the dragged element.
16483 * @method getBestMatch
16484 * @param {DragDrop[]} dds The array of drag and drop objects
16486 * @return {DragDrop} The best single match
16489 getBestMatch: function(dds) {
16491 // Return null if the input is not what we expect
16492 //if (!dds || !dds.length || dds.length == 0) {
16494 // If there is only one item, it wins
16495 //} else if (dds.length == 1) {
16497 var len = dds.length;
16502 // Loop through the targeted items
16503 for (var i=0; i<len; ++i) {
16505 // If the cursor is over the object, it wins. If the
16506 // cursor is over multiple matches, the first one we come
16508 if (dd.cursorIsOver) {
16511 // Otherwise the object with the most overlap wins
16514 winner.overlap.getArea() < dd.overlap.getArea()) {
16525 * Refreshes the cache of the top-left and bottom-right points of the
16526 * drag and drop objects in the specified group(s). This is in the
16527 * format that is stored in the drag and drop instance, so typical
16530 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16534 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16536 * @TODO this really should be an indexed array. Alternatively this
16537 * method could accept both.
16538 * @method refreshCache
16539 * @param {Object} groups an associative array of groups to refresh
16542 refreshCache: function(groups) {
16543 for (var sGroup in groups) {
16544 if ("string" != typeof sGroup) {
16547 for (var i in this.ids[sGroup]) {
16548 var oDD = this.ids[sGroup][i];
16550 if (this.isTypeOfDD(oDD)) {
16551 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16552 var loc = this.getLocation(oDD);
16554 this.locationCache[oDD.id] = loc;
16556 delete this.locationCache[oDD.id];
16557 // this will unregister the drag and drop object if
16558 // the element is not in a usable state
16567 * This checks to make sure an element exists and is in the DOM. The
16568 * main purpose is to handle cases where innerHTML is used to remove
16569 * drag and drop objects from the DOM. IE provides an 'unspecified
16570 * error' when trying to access the offsetParent of such an element
16572 * @param {HTMLElement} el the element to check
16573 * @return {boolean} true if the element looks usable
16576 verifyEl: function(el) {
16581 parent = el.offsetParent;
16584 parent = el.offsetParent;
16595 * Returns a Region object containing the drag and drop element's position
16596 * and size, including the padding configured for it
16597 * @method getLocation
16598 * @param {DragDrop} oDD the drag and drop object to get the
16600 * @return {Roo.lib.Region} a Region object representing the total area
16601 * the element occupies, including any padding
16602 * the instance is configured for.
16605 getLocation: function(oDD) {
16606 if (! this.isTypeOfDD(oDD)) {
16610 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16613 pos= Roo.lib.Dom.getXY(el);
16621 x2 = x1 + el.offsetWidth;
16623 y2 = y1 + el.offsetHeight;
16625 t = y1 - oDD.padding[0];
16626 r = x2 + oDD.padding[1];
16627 b = y2 + oDD.padding[2];
16628 l = x1 - oDD.padding[3];
16630 return new Roo.lib.Region( t, r, b, l );
16634 * Checks the cursor location to see if it over the target
16635 * @method isOverTarget
16636 * @param {Roo.lib.Point} pt The point to evaluate
16637 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16638 * @return {boolean} true if the mouse is over the target
16642 isOverTarget: function(pt, oTarget, intersect) {
16643 // use cache if available
16644 var loc = this.locationCache[oTarget.id];
16645 if (!loc || !this.useCache) {
16646 loc = this.getLocation(oTarget);
16647 this.locationCache[oTarget.id] = loc;
16655 oTarget.cursorIsOver = loc.contains( pt );
16657 // DragDrop is using this as a sanity check for the initial mousedown
16658 // in this case we are done. In POINT mode, if the drag obj has no
16659 // contraints, we are also done. Otherwise we need to evaluate the
16660 // location of the target as related to the actual location of the
16661 // dragged element.
16662 var dc = this.dragCurrent;
16663 if (!dc || !dc.getTargetCoord ||
16664 (!intersect && !dc.constrainX && !dc.constrainY)) {
16665 return oTarget.cursorIsOver;
16668 oTarget.overlap = null;
16670 // Get the current location of the drag element, this is the
16671 // location of the mouse event less the delta that represents
16672 // where the original mousedown happened on the element. We
16673 // need to consider constraints and ticks as well.
16674 var pos = dc.getTargetCoord(pt.x, pt.y);
16676 var el = dc.getDragEl();
16677 var curRegion = new Roo.lib.Region( pos.y,
16678 pos.x + el.offsetWidth,
16679 pos.y + el.offsetHeight,
16682 var overlap = curRegion.intersect(loc);
16685 oTarget.overlap = overlap;
16686 return (intersect) ? true : oTarget.cursorIsOver;
16693 * unload event handler
16694 * @method _onUnload
16698 _onUnload: function(e, me) {
16699 Roo.dd.DragDropMgr.unregAll();
16703 * Cleans up the drag and drop events and objects.
16708 unregAll: function() {
16710 if (this.dragCurrent) {
16712 this.dragCurrent = null;
16715 this._execOnAll("unreg", []);
16717 for (i in this.elementCache) {
16718 delete this.elementCache[i];
16721 this.elementCache = {};
16726 * A cache of DOM elements
16727 * @property elementCache
16734 * Get the wrapper for the DOM element specified
16735 * @method getElWrapper
16736 * @param {String} id the id of the element to get
16737 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16739 * @deprecated This wrapper isn't that useful
16742 getElWrapper: function(id) {
16743 var oWrapper = this.elementCache[id];
16744 if (!oWrapper || !oWrapper.el) {
16745 oWrapper = this.elementCache[id] =
16746 new this.ElementWrapper(Roo.getDom(id));
16752 * Returns the actual DOM element
16753 * @method getElement
16754 * @param {String} id the id of the elment to get
16755 * @return {Object} The element
16756 * @deprecated use Roo.getDom instead
16759 getElement: function(id) {
16760 return Roo.getDom(id);
16764 * Returns the style property for the DOM element (i.e.,
16765 * document.getElById(id).style)
16767 * @param {String} id the id of the elment to get
16768 * @return {Object} The style property of the element
16769 * @deprecated use Roo.getDom instead
16772 getCss: function(id) {
16773 var el = Roo.getDom(id);
16774 return (el) ? el.style : null;
16778 * Inner class for cached elements
16779 * @class DragDropMgr.ElementWrapper
16784 ElementWrapper: function(el) {
16789 this.el = el || null;
16794 this.id = this.el && el.id;
16796 * A reference to the style property
16799 this.css = this.el && el.style;
16803 * Returns the X position of an html element
16805 * @param el the element for which to get the position
16806 * @return {int} the X coordinate
16808 * @deprecated use Roo.lib.Dom.getX instead
16811 getPosX: function(el) {
16812 return Roo.lib.Dom.getX(el);
16816 * Returns the Y position of an html element
16818 * @param el the element for which to get the position
16819 * @return {int} the Y coordinate
16820 * @deprecated use Roo.lib.Dom.getY instead
16823 getPosY: function(el) {
16824 return Roo.lib.Dom.getY(el);
16828 * Swap two nodes. In IE, we use the native method, for others we
16829 * emulate the IE behavior
16831 * @param n1 the first node to swap
16832 * @param n2 the other node to swap
16835 swapNode: function(n1, n2) {
16839 var p = n2.parentNode;
16840 var s = n2.nextSibling;
16843 p.insertBefore(n1, n2);
16844 } else if (n2 == n1.nextSibling) {
16845 p.insertBefore(n2, n1);
16847 n1.parentNode.replaceChild(n2, n1);
16848 p.insertBefore(n1, s);
16854 * Returns the current scroll position
16855 * @method getScroll
16859 getScroll: function () {
16860 var t, l, dde=document.documentElement, db=document.body;
16861 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16863 l = dde.scrollLeft;
16870 return { top: t, left: l };
16874 * Returns the specified element style property
16876 * @param {HTMLElement} el the element
16877 * @param {string} styleProp the style property
16878 * @return {string} The value of the style property
16879 * @deprecated use Roo.lib.Dom.getStyle
16882 getStyle: function(el, styleProp) {
16883 return Roo.fly(el).getStyle(styleProp);
16887 * Gets the scrollTop
16888 * @method getScrollTop
16889 * @return {int} the document's scrollTop
16892 getScrollTop: function () { return this.getScroll().top; },
16895 * Gets the scrollLeft
16896 * @method getScrollLeft
16897 * @return {int} the document's scrollTop
16900 getScrollLeft: function () { return this.getScroll().left; },
16903 * Sets the x/y position of an element to the location of the
16906 * @param {HTMLElement} moveEl The element to move
16907 * @param {HTMLElement} targetEl The position reference element
16910 moveToEl: function (moveEl, targetEl) {
16911 var aCoord = Roo.lib.Dom.getXY(targetEl);
16912 Roo.lib.Dom.setXY(moveEl, aCoord);
16916 * Numeric array sort function
16917 * @method numericSort
16920 numericSort: function(a, b) { return (a - b); },
16924 * @property _timeoutCount
16931 * Trying to make the load order less important. Without this we get
16932 * an error if this file is loaded before the Event Utility.
16933 * @method _addListeners
16937 _addListeners: function() {
16938 var DDM = Roo.dd.DDM;
16939 if ( Roo.lib.Event && document ) {
16942 if (DDM._timeoutCount > 2000) {
16944 setTimeout(DDM._addListeners, 10);
16945 if (document && document.body) {
16946 DDM._timeoutCount += 1;
16953 * Recursively searches the immediate parent and all child nodes for
16954 * the handle element in order to determine wheter or not it was
16956 * @method handleWasClicked
16957 * @param node the html element to inspect
16960 handleWasClicked: function(node, id) {
16961 if (this.isHandle(id, node.id)) {
16964 // check to see if this is a text node child of the one we want
16965 var p = node.parentNode;
16968 if (this.isHandle(id, p.id)) {
16983 // shorter alias, save a few bytes
16984 Roo.dd.DDM = Roo.dd.DragDropMgr;
16985 Roo.dd.DDM._addListeners();
16989 * Ext JS Library 1.1.1
16990 * Copyright(c) 2006-2007, Ext JS, LLC.
16992 * Originally Released Under LGPL - original licence link has changed is not relivant.
16995 * <script type="text/javascript">
17000 * A DragDrop implementation where the linked element follows the
17001 * mouse cursor during a drag.
17002 * @extends Roo.dd.DragDrop
17004 * @param {String} id the id of the linked element
17005 * @param {String} sGroup the group of related DragDrop items
17006 * @param {object} config an object containing configurable attributes
17007 * Valid properties for DD:
17010 Roo.dd.DD = function(id, sGroup, config) {
17012 this.init(id, sGroup, config);
17016 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17019 * When set to true, the utility automatically tries to scroll the browser
17020 * window wehn a drag and drop element is dragged near the viewport boundary.
17021 * Defaults to true.
17028 * Sets the pointer offset to the distance between the linked element's top
17029 * left corner and the location the element was clicked
17030 * @method autoOffset
17031 * @param {int} iPageX the X coordinate of the click
17032 * @param {int} iPageY the Y coordinate of the click
17034 autoOffset: function(iPageX, iPageY) {
17035 var x = iPageX - this.startPageX;
17036 var y = iPageY - this.startPageY;
17037 this.setDelta(x, y);
17041 * Sets the pointer offset. You can call this directly to force the
17042 * offset to be in a particular location (e.g., pass in 0,0 to set it
17043 * to the center of the object)
17045 * @param {int} iDeltaX the distance from the left
17046 * @param {int} iDeltaY the distance from the top
17048 setDelta: function(iDeltaX, iDeltaY) {
17049 this.deltaX = iDeltaX;
17050 this.deltaY = iDeltaY;
17054 * Sets the drag 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 setDragElPos
17059 * @param {int} iPageX the X coordinate of the mousedown or drag event
17060 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17062 setDragElPos: function(iPageX, iPageY) {
17063 // the first time we do this, we are going to check to make sure
17064 // the element has css positioning
17066 var el = this.getDragEl();
17067 this.alignElWithMouse(el, iPageX, iPageY);
17071 * Sets the element to the location of the mousedown or click event,
17072 * maintaining the cursor location relative to the location on the element
17073 * that was clicked. Override this if you want to place the element in a
17074 * location other than where the cursor is.
17075 * @method alignElWithMouse
17076 * @param {HTMLElement} el the element to move
17077 * @param {int} iPageX the X coordinate of the mousedown or drag event
17078 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17080 alignElWithMouse: function(el, iPageX, iPageY) {
17081 var oCoord = this.getTargetCoord(iPageX, iPageY);
17082 var fly = el.dom ? el : Roo.fly(el);
17083 if (!this.deltaSetXY) {
17084 var aCoord = [oCoord.x, oCoord.y];
17086 var newLeft = fly.getLeft(true);
17087 var newTop = fly.getTop(true);
17088 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17090 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17093 this.cachePosition(oCoord.x, oCoord.y);
17094 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17099 * Saves the most recent position so that we can reset the constraints and
17100 * tick marks on-demand. We need to know this so that we can calculate the
17101 * number of pixels the element is offset from its original position.
17102 * @method cachePosition
17103 * @param iPageX the current x position (optional, this just makes it so we
17104 * don't have to look it up again)
17105 * @param iPageY the current y position (optional, this just makes it so we
17106 * don't have to look it up again)
17108 cachePosition: function(iPageX, iPageY) {
17110 this.lastPageX = iPageX;
17111 this.lastPageY = iPageY;
17113 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17114 this.lastPageX = aCoord[0];
17115 this.lastPageY = aCoord[1];
17120 * Auto-scroll the window if the dragged object has been moved beyond the
17121 * visible window boundary.
17122 * @method autoScroll
17123 * @param {int} x the drag element's x position
17124 * @param {int} y the drag element's y position
17125 * @param {int} h the height of the drag element
17126 * @param {int} w the width of the drag element
17129 autoScroll: function(x, y, h, w) {
17132 // The client height
17133 var clientH = Roo.lib.Dom.getViewWidth();
17135 // The client width
17136 var clientW = Roo.lib.Dom.getViewHeight();
17138 // The amt scrolled down
17139 var st = this.DDM.getScrollTop();
17141 // The amt scrolled right
17142 var sl = this.DDM.getScrollLeft();
17144 // Location of the bottom of the element
17147 // Location of the right of the element
17150 // The distance from the cursor to the bottom of the visible area,
17151 // adjusted so that we don't scroll if the cursor is beyond the
17152 // element drag constraints
17153 var toBot = (clientH + st - y - this.deltaY);
17155 // The distance from the cursor to the right of the visible area
17156 var toRight = (clientW + sl - x - this.deltaX);
17159 // How close to the edge the cursor must be before we scroll
17160 // var thresh = (document.all) ? 100 : 40;
17163 // How many pixels to scroll per autoscroll op. This helps to reduce
17164 // clunky scrolling. IE is more sensitive about this ... it needs this
17165 // value to be higher.
17166 var scrAmt = (document.all) ? 80 : 30;
17168 // Scroll down if we are near the bottom of the visible page and the
17169 // obj extends below the crease
17170 if ( bot > clientH && toBot < thresh ) {
17171 window.scrollTo(sl, st + scrAmt);
17174 // Scroll up if the window is scrolled down and the top of the object
17175 // goes above the top border
17176 if ( y < st && st > 0 && y - st < thresh ) {
17177 window.scrollTo(sl, st - scrAmt);
17180 // Scroll right if the obj is beyond the right border and the cursor is
17181 // near the border.
17182 if ( right > clientW && toRight < thresh ) {
17183 window.scrollTo(sl + scrAmt, st);
17186 // Scroll left if the window has been scrolled to the right and the obj
17187 // extends past the left border
17188 if ( x < sl && sl > 0 && x - sl < thresh ) {
17189 window.scrollTo(sl - scrAmt, st);
17195 * Finds the location the element should be placed if we want to move
17196 * it to where the mouse location less the click offset would place us.
17197 * @method getTargetCoord
17198 * @param {int} iPageX the X coordinate of the click
17199 * @param {int} iPageY the Y coordinate of the click
17200 * @return an object that contains the coordinates (Object.x and Object.y)
17203 getTargetCoord: function(iPageX, iPageY) {
17206 var x = iPageX - this.deltaX;
17207 var y = iPageY - this.deltaY;
17209 if (this.constrainX) {
17210 if (x < this.minX) { x = this.minX; }
17211 if (x > this.maxX) { x = this.maxX; }
17214 if (this.constrainY) {
17215 if (y < this.minY) { y = this.minY; }
17216 if (y > this.maxY) { y = this.maxY; }
17219 x = this.getTick(x, this.xTicks);
17220 y = this.getTick(y, this.yTicks);
17227 * Sets up config options specific to this class. Overrides
17228 * Roo.dd.DragDrop, but all versions of this method through the
17229 * inheritance chain are called
17231 applyConfig: function() {
17232 Roo.dd.DD.superclass.applyConfig.call(this);
17233 this.scroll = (this.config.scroll !== false);
17237 * Event that fires prior to the onMouseDown event. Overrides
17240 b4MouseDown: function(e) {
17241 // this.resetConstraints();
17242 this.autoOffset(e.getPageX(),
17247 * Event that fires prior to the onDrag event. Overrides
17250 b4Drag: function(e) {
17251 this.setDragElPos(e.getPageX(),
17255 toString: function() {
17256 return ("DD " + this.id);
17259 //////////////////////////////////////////////////////////////////////////
17260 // Debugging ygDragDrop events that can be overridden
17261 //////////////////////////////////////////////////////////////////////////
17263 startDrag: function(x, y) {
17266 onDrag: function(e) {
17269 onDragEnter: function(e, id) {
17272 onDragOver: function(e, id) {
17275 onDragOut: function(e, id) {
17278 onDragDrop: function(e, id) {
17281 endDrag: function(e) {
17288 * Ext JS Library 1.1.1
17289 * Copyright(c) 2006-2007, Ext JS, LLC.
17291 * Originally Released Under LGPL - original licence link has changed is not relivant.
17294 * <script type="text/javascript">
17298 * @class Roo.dd.DDProxy
17299 * A DragDrop implementation that inserts an empty, bordered div into
17300 * the document that follows the cursor during drag operations. At the time of
17301 * the click, the frame div is resized to the dimensions of the linked html
17302 * element, and moved to the exact location of the linked element.
17304 * References to the "frame" element refer to the single proxy element that
17305 * was created to be dragged in place of all DDProxy elements on the
17308 * @extends Roo.dd.DD
17310 * @param {String} id the id of the linked html element
17311 * @param {String} sGroup the group of related DragDrop objects
17312 * @param {object} config an object containing configurable attributes
17313 * Valid properties for DDProxy in addition to those in DragDrop:
17314 * resizeFrame, centerFrame, dragElId
17316 Roo.dd.DDProxy = function(id, sGroup, config) {
17318 this.init(id, sGroup, config);
17324 * The default drag frame div id
17325 * @property Roo.dd.DDProxy.dragElId
17329 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17331 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17334 * By default we resize the drag frame to be the same size as the element
17335 * we want to drag (this is to get the frame effect). We can turn it off
17336 * if we want a different behavior.
17337 * @property resizeFrame
17343 * By default the frame is positioned exactly where the drag element is, so
17344 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17345 * you do not have constraints on the obj is to have the drag frame centered
17346 * around the cursor. Set centerFrame to true for this effect.
17347 * @property centerFrame
17350 centerFrame: false,
17353 * Creates the proxy element if it does not yet exist
17354 * @method createFrame
17356 createFrame: function() {
17358 var body = document.body;
17360 if (!body || !body.firstChild) {
17361 setTimeout( function() { self.createFrame(); }, 50 );
17365 var div = this.getDragEl();
17368 div = document.createElement("div");
17369 div.id = this.dragElId;
17372 s.position = "absolute";
17373 s.visibility = "hidden";
17375 s.border = "2px solid #aaa";
17378 // appendChild can blow up IE if invoked prior to the window load event
17379 // while rendering a table. It is possible there are other scenarios
17380 // that would cause this to happen as well.
17381 body.insertBefore(div, body.firstChild);
17386 * Initialization for the drag frame element. Must be called in the
17387 * constructor of all subclasses
17388 * @method initFrame
17390 initFrame: function() {
17391 this.createFrame();
17394 applyConfig: function() {
17395 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17397 this.resizeFrame = (this.config.resizeFrame !== false);
17398 this.centerFrame = (this.config.centerFrame);
17399 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17403 * Resizes the drag frame to the dimensions of the clicked object, positions
17404 * it over the object, and finally displays it
17405 * @method showFrame
17406 * @param {int} iPageX X click position
17407 * @param {int} iPageY Y click position
17410 showFrame: function(iPageX, iPageY) {
17411 var el = this.getEl();
17412 var dragEl = this.getDragEl();
17413 var s = dragEl.style;
17415 this._resizeProxy();
17417 if (this.centerFrame) {
17418 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17419 Math.round(parseInt(s.height, 10)/2) );
17422 this.setDragElPos(iPageX, iPageY);
17424 Roo.fly(dragEl).show();
17428 * The proxy is automatically resized to the dimensions of the linked
17429 * element when a drag is initiated, unless resizeFrame is set to false
17430 * @method _resizeProxy
17433 _resizeProxy: function() {
17434 if (this.resizeFrame) {
17435 var el = this.getEl();
17436 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17440 // overrides Roo.dd.DragDrop
17441 b4MouseDown: function(e) {
17442 var x = e.getPageX();
17443 var y = e.getPageY();
17444 this.autoOffset(x, y);
17445 this.setDragElPos(x, y);
17448 // overrides Roo.dd.DragDrop
17449 b4StartDrag: function(x, y) {
17450 // show the drag frame
17451 this.showFrame(x, y);
17454 // overrides Roo.dd.DragDrop
17455 b4EndDrag: function(e) {
17456 Roo.fly(this.getDragEl()).hide();
17459 // overrides Roo.dd.DragDrop
17460 // By default we try to move the element to the last location of the frame.
17461 // This is so that the default behavior mirrors that of Roo.dd.DD.
17462 endDrag: function(e) {
17464 var lel = this.getEl();
17465 var del = this.getDragEl();
17467 // Show the drag frame briefly so we can get its position
17468 del.style.visibility = "";
17471 // Hide the linked element before the move to get around a Safari
17473 lel.style.visibility = "hidden";
17474 Roo.dd.DDM.moveToEl(lel, del);
17475 del.style.visibility = "hidden";
17476 lel.style.visibility = "";
17481 beforeMove : function(){
17485 afterDrag : function(){
17489 toString: function() {
17490 return ("DDProxy " + this.id);
17496 * Ext JS Library 1.1.1
17497 * Copyright(c) 2006-2007, Ext JS, LLC.
17499 * Originally Released Under LGPL - original licence link has changed is not relivant.
17502 * <script type="text/javascript">
17506 * @class Roo.dd.DDTarget
17507 * A DragDrop implementation that does not move, but can be a drop
17508 * target. You would get the same result by simply omitting implementation
17509 * for the event callbacks, but this way we reduce the processing cost of the
17510 * event listener and the callbacks.
17511 * @extends Roo.dd.DragDrop
17513 * @param {String} id the id of the element that is a drop target
17514 * @param {String} sGroup the group of related DragDrop objects
17515 * @param {object} config an object containing configurable attributes
17516 * Valid properties for DDTarget in addition to those in
17520 Roo.dd.DDTarget = function(id, sGroup, config) {
17522 this.initTarget(id, sGroup, config);
17524 if (config.listeners || config.events) {
17525 Roo.dd.DragDrop.superclass.constructor.call(this, {
17526 listeners : config.listeners || {},
17527 events : config.events || {}
17532 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17533 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17534 toString: function() {
17535 return ("DDTarget " + this.id);
17540 * Ext JS Library 1.1.1
17541 * Copyright(c) 2006-2007, Ext JS, LLC.
17543 * Originally Released Under LGPL - original licence link has changed is not relivant.
17546 * <script type="text/javascript">
17551 * @class Roo.dd.ScrollManager
17552 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17553 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17556 Roo.dd.ScrollManager = function(){
17557 var ddm = Roo.dd.DragDropMgr;
17562 var onStop = function(e){
17567 var triggerRefresh = function(){
17568 if(ddm.dragCurrent){
17569 ddm.refreshCache(ddm.dragCurrent.groups);
17573 var doScroll = function(){
17574 if(ddm.dragCurrent){
17575 var dds = Roo.dd.ScrollManager;
17577 if(proc.el.scroll(proc.dir, dds.increment)){
17581 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17586 var clearProc = function(){
17588 clearInterval(proc.id);
17595 var startProc = function(el, dir){
17599 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17602 var onFire = function(e, isDrop){
17603 if(isDrop || !ddm.dragCurrent){ return; }
17604 var dds = Roo.dd.ScrollManager;
17605 if(!dragEl || dragEl != ddm.dragCurrent){
17606 dragEl = ddm.dragCurrent;
17607 // refresh regions on drag start
17608 dds.refreshCache();
17611 var xy = Roo.lib.Event.getXY(e);
17612 var pt = new Roo.lib.Point(xy[0], xy[1]);
17613 for(var id in els){
17614 var el = els[id], r = el._region;
17615 if(r && r.contains(pt) && el.isScrollable()){
17616 if(r.bottom - pt.y <= dds.thresh){
17618 startProc(el, "down");
17621 }else if(r.right - pt.x <= dds.thresh){
17623 startProc(el, "left");
17626 }else if(pt.y - r.top <= dds.thresh){
17628 startProc(el, "up");
17631 }else if(pt.x - r.left <= dds.thresh){
17633 startProc(el, "right");
17642 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17643 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17647 * Registers new overflow element(s) to auto scroll
17648 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17650 register : function(el){
17651 if(el instanceof Array){
17652 for(var i = 0, len = el.length; i < len; i++) {
17653 this.register(el[i]);
17662 * Unregisters overflow element(s) so they are no longer scrolled
17663 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17665 unregister : function(el){
17666 if(el instanceof Array){
17667 for(var i = 0, len = el.length; i < len; i++) {
17668 this.unregister(el[i]);
17677 * The number of pixels from the edge of a container the pointer needs to be to
17678 * trigger scrolling (defaults to 25)
17684 * The number of pixels to scroll in each scroll increment (defaults to 50)
17690 * The frequency of scrolls in milliseconds (defaults to 500)
17696 * True to animate the scroll (defaults to true)
17702 * The animation duration in seconds -
17703 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17709 * Manually trigger a cache refresh.
17711 refreshCache : function(){
17712 for(var id in els){
17713 if(typeof els[id] == 'object'){ // for people extending the object prototype
17714 els[id]._region = els[id].getRegion();
17721 * Ext JS Library 1.1.1
17722 * Copyright(c) 2006-2007, Ext JS, LLC.
17724 * Originally Released Under LGPL - original licence link has changed is not relivant.
17727 * <script type="text/javascript">
17732 * @class Roo.dd.Registry
17733 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17734 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17737 Roo.dd.Registry = function(){
17740 var autoIdSeed = 0;
17742 var getId = function(el, autogen){
17743 if(typeof el == "string"){
17747 if(!id && autogen !== false){
17748 id = "roodd-" + (++autoIdSeed);
17756 * Register a drag drop element
17757 * @param {String|HTMLElement} element The id or DOM node to register
17758 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17759 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17760 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17761 * populated in the data object (if applicable):
17763 Value Description<br />
17764 --------- ------------------------------------------<br />
17765 handles Array of DOM nodes that trigger dragging<br />
17766 for the element being registered<br />
17767 isHandle True if the element passed in triggers<br />
17768 dragging itself, else false
17771 register : function(el, data){
17773 if(typeof el == "string"){
17774 el = document.getElementById(el);
17777 elements[getId(el)] = data;
17778 if(data.isHandle !== false){
17779 handles[data.ddel.id] = data;
17782 var hs = data.handles;
17783 for(var i = 0, len = hs.length; i < len; i++){
17784 handles[getId(hs[i])] = data;
17790 * Unregister a drag drop element
17791 * @param {String|HTMLElement} element The id or DOM node to unregister
17793 unregister : function(el){
17794 var id = getId(el, false);
17795 var data = elements[id];
17797 delete elements[id];
17799 var hs = data.handles;
17800 for(var i = 0, len = hs.length; i < len; i++){
17801 delete handles[getId(hs[i], false)];
17808 * Returns the handle registered for a DOM Node by id
17809 * @param {String|HTMLElement} id The DOM node or id to look up
17810 * @return {Object} handle The custom handle data
17812 getHandle : function(id){
17813 if(typeof id != "string"){ // must be element?
17816 return handles[id];
17820 * Returns the handle that is registered for the DOM node that is the target of the event
17821 * @param {Event} e The event
17822 * @return {Object} handle The custom handle data
17824 getHandleFromEvent : function(e){
17825 var t = Roo.lib.Event.getTarget(e);
17826 return t ? handles[t.id] : null;
17830 * Returns a custom data object that is registered for a DOM node by id
17831 * @param {String|HTMLElement} id The DOM node or id to look up
17832 * @return {Object} data The custom data
17834 getTarget : function(id){
17835 if(typeof id != "string"){ // must be element?
17838 return elements[id];
17842 * Returns a custom data object that is registered for the DOM node that is the target of the event
17843 * @param {Event} e The event
17844 * @return {Object} data The custom data
17846 getTargetFromEvent : function(e){
17847 var t = Roo.lib.Event.getTarget(e);
17848 return t ? elements[t.id] || handles[t.id] : null;
17853 * Ext JS Library 1.1.1
17854 * Copyright(c) 2006-2007, Ext JS, LLC.
17856 * Originally Released Under LGPL - original licence link has changed is not relivant.
17859 * <script type="text/javascript">
17864 * @class Roo.dd.StatusProxy
17865 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17866 * default drag proxy used by all Roo.dd components.
17868 * @param {Object} config
17870 Roo.dd.StatusProxy = function(config){
17871 Roo.apply(this, config);
17872 this.id = this.id || Roo.id();
17873 this.el = new Roo.Layer({
17875 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17876 {tag: "div", cls: "x-dd-drop-icon"},
17877 {tag: "div", cls: "x-dd-drag-ghost"}
17880 shadow: !config || config.shadow !== false
17882 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17883 this.dropStatus = this.dropNotAllowed;
17886 Roo.dd.StatusProxy.prototype = {
17888 * @cfg {String} dropAllowed
17889 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17891 dropAllowed : "x-dd-drop-ok",
17893 * @cfg {String} dropNotAllowed
17894 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17896 dropNotAllowed : "x-dd-drop-nodrop",
17899 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17900 * over the current target element.
17901 * @param {String} cssClass The css class for the new drop status indicator image
17903 setStatus : function(cssClass){
17904 cssClass = cssClass || this.dropNotAllowed;
17905 if(this.dropStatus != cssClass){
17906 this.el.replaceClass(this.dropStatus, cssClass);
17907 this.dropStatus = cssClass;
17912 * Resets the status indicator to the default dropNotAllowed value
17913 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17915 reset : function(clearGhost){
17916 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17917 this.dropStatus = this.dropNotAllowed;
17919 this.ghost.update("");
17924 * Updates the contents of the ghost element
17925 * @param {String} html The html that will replace the current innerHTML of the ghost element
17927 update : function(html){
17928 if(typeof html == "string"){
17929 this.ghost.update(html);
17931 this.ghost.update("");
17932 html.style.margin = "0";
17933 this.ghost.dom.appendChild(html);
17935 // ensure float = none set?? cant remember why though.
17936 var el = this.ghost.dom.firstChild;
17938 Roo.fly(el).setStyle('float', 'none');
17943 * Returns the underlying proxy {@link Roo.Layer}
17944 * @return {Roo.Layer} el
17946 getEl : function(){
17951 * Returns the ghost element
17952 * @return {Roo.Element} el
17954 getGhost : function(){
17960 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17962 hide : function(clear){
17970 * Stops the repair animation if it's currently running
17973 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17979 * Displays this proxy
17986 * Force the Layer to sync its shadow and shim positions to the element
17993 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17994 * invalid drop operation by the item being dragged.
17995 * @param {Array} xy The XY position of the element ([x, y])
17996 * @param {Function} callback The function to call after the repair is complete
17997 * @param {Object} scope The scope in which to execute the callback
17999 repair : function(xy, callback, scope){
18000 this.callback = callback;
18001 this.scope = scope;
18002 if(xy && this.animRepair !== false){
18003 this.el.addClass("x-dd-drag-repair");
18004 this.el.hideUnders(true);
18005 this.anim = this.el.shift({
18006 duration: this.repairDuration || .5,
18010 callback: this.afterRepair,
18014 this.afterRepair();
18019 afterRepair : function(){
18021 if(typeof this.callback == "function"){
18022 this.callback.call(this.scope || this);
18024 this.callback = null;
18029 * Ext JS Library 1.1.1
18030 * Copyright(c) 2006-2007, Ext JS, LLC.
18032 * Originally Released Under LGPL - original licence link has changed is not relivant.
18035 * <script type="text/javascript">
18039 * @class Roo.dd.DragSource
18040 * @extends Roo.dd.DDProxy
18041 * A simple class that provides the basic implementation needed to make any element draggable.
18043 * @param {String/HTMLElement/Element} el The container element
18044 * @param {Object} config
18046 Roo.dd.DragSource = function(el, config){
18047 this.el = Roo.get(el);
18048 this.dragData = {};
18050 Roo.apply(this, config);
18053 this.proxy = new Roo.dd.StatusProxy();
18056 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18057 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18059 this.dragging = false;
18062 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18064 * @cfg {String} dropAllowed
18065 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18067 dropAllowed : "x-dd-drop-ok",
18069 * @cfg {String} dropNotAllowed
18070 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18072 dropNotAllowed : "x-dd-drop-nodrop",
18075 * Returns the data object associated with this drag source
18076 * @return {Object} data An object containing arbitrary data
18078 getDragData : function(e){
18079 return this.dragData;
18083 onDragEnter : function(e, id){
18084 var target = Roo.dd.DragDropMgr.getDDById(id);
18085 this.cachedTarget = target;
18086 if(this.beforeDragEnter(target, e, id) !== false){
18087 if(target.isNotifyTarget){
18088 var status = target.notifyEnter(this, e, this.dragData);
18089 this.proxy.setStatus(status);
18091 this.proxy.setStatus(this.dropAllowed);
18094 if(this.afterDragEnter){
18096 * An empty function by default, but provided so that you can perform a custom action
18097 * when the dragged item enters the drop target by providing an implementation.
18098 * @param {Roo.dd.DragDrop} target The drop target
18099 * @param {Event} e The event object
18100 * @param {String} id The id of the dragged element
18101 * @method afterDragEnter
18103 this.afterDragEnter(target, e, id);
18109 * An empty function by default, but provided so that you can perform a custom action
18110 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18111 * @param {Roo.dd.DragDrop} target The drop target
18112 * @param {Event} e The event object
18113 * @param {String} id The id of the dragged element
18114 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18116 beforeDragEnter : function(target, e, id){
18121 alignElWithMouse: function() {
18122 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18127 onDragOver : function(e, id){
18128 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18129 if(this.beforeDragOver(target, e, id) !== false){
18130 if(target.isNotifyTarget){
18131 var status = target.notifyOver(this, e, this.dragData);
18132 this.proxy.setStatus(status);
18135 if(this.afterDragOver){
18137 * An empty function by default, but provided so that you can perform a custom action
18138 * while the dragged item is over the drop target by providing an implementation.
18139 * @param {Roo.dd.DragDrop} target The drop target
18140 * @param {Event} e The event object
18141 * @param {String} id The id of the dragged element
18142 * @method afterDragOver
18144 this.afterDragOver(target, e, id);
18150 * An empty function by default, but provided so that you can perform a custom action
18151 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18152 * @param {Roo.dd.DragDrop} target The drop target
18153 * @param {Event} e The event object
18154 * @param {String} id The id of the dragged element
18155 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18157 beforeDragOver : function(target, e, id){
18162 onDragOut : function(e, id){
18163 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18164 if(this.beforeDragOut(target, e, id) !== false){
18165 if(target.isNotifyTarget){
18166 target.notifyOut(this, e, this.dragData);
18168 this.proxy.reset();
18169 if(this.afterDragOut){
18171 * An empty function by default, but provided so that you can perform a custom action
18172 * after the dragged item is dragged out of the target without dropping.
18173 * @param {Roo.dd.DragDrop} target The drop target
18174 * @param {Event} e The event object
18175 * @param {String} id The id of the dragged element
18176 * @method afterDragOut
18178 this.afterDragOut(target, e, id);
18181 this.cachedTarget = null;
18185 * An empty function by default, but provided so that you can perform a custom action before the dragged
18186 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18187 * @param {Roo.dd.DragDrop} target The drop target
18188 * @param {Event} e The event object
18189 * @param {String} id The id of the dragged element
18190 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18192 beforeDragOut : function(target, e, id){
18197 onDragDrop : function(e, id){
18198 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18199 if(this.beforeDragDrop(target, e, id) !== false){
18200 if(target.isNotifyTarget){
18201 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18202 this.onValidDrop(target, e, id);
18204 this.onInvalidDrop(target, e, id);
18207 this.onValidDrop(target, e, id);
18210 if(this.afterDragDrop){
18212 * An empty function by default, but provided so that you can perform a custom action
18213 * after a valid drag drop has occurred by providing an implementation.
18214 * @param {Roo.dd.DragDrop} target The drop target
18215 * @param {Event} e The event object
18216 * @param {String} id The id of the dropped element
18217 * @method afterDragDrop
18219 this.afterDragDrop(target, e, id);
18222 delete this.cachedTarget;
18226 * An empty function by default, but provided so that you can perform a custom action before the dragged
18227 * item is dropped onto the target and optionally cancel the onDragDrop.
18228 * @param {Roo.dd.DragDrop} target The drop target
18229 * @param {Event} e The event object
18230 * @param {String} id The id of the dragged element
18231 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18233 beforeDragDrop : function(target, e, id){
18238 onValidDrop : function(target, e, id){
18240 if(this.afterValidDrop){
18242 * An empty function by default, but provided so that you can perform a custom action
18243 * after a valid drop has occurred by providing an implementation.
18244 * @param {Object} target The target DD
18245 * @param {Event} e The event object
18246 * @param {String} id The id of the dropped element
18247 * @method afterInvalidDrop
18249 this.afterValidDrop(target, e, id);
18254 getRepairXY : function(e, data){
18255 return this.el.getXY();
18259 onInvalidDrop : function(target, e, id){
18260 this.beforeInvalidDrop(target, e, id);
18261 if(this.cachedTarget){
18262 if(this.cachedTarget.isNotifyTarget){
18263 this.cachedTarget.notifyOut(this, e, this.dragData);
18265 this.cacheTarget = null;
18267 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18269 if(this.afterInvalidDrop){
18271 * An empty function by default, but provided so that you can perform a custom action
18272 * after an invalid drop has occurred by providing an implementation.
18273 * @param {Event} e The event object
18274 * @param {String} id The id of the dropped element
18275 * @method afterInvalidDrop
18277 this.afterInvalidDrop(e, id);
18282 afterRepair : function(){
18284 this.el.highlight(this.hlColor || "c3daf9");
18286 this.dragging = false;
18290 * An empty function by default, but provided so that you can perform a custom action after an invalid
18291 * drop has occurred.
18292 * @param {Roo.dd.DragDrop} target The drop target
18293 * @param {Event} e The event object
18294 * @param {String} id The id of the dragged element
18295 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18297 beforeInvalidDrop : function(target, e, id){
18302 handleMouseDown : function(e){
18303 if(this.dragging) {
18306 var data = this.getDragData(e);
18307 if(data && this.onBeforeDrag(data, e) !== false){
18308 this.dragData = data;
18310 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18315 * An empty function by default, but provided so that you can perform a custom action before the initial
18316 * drag event begins and optionally cancel it.
18317 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18318 * @param {Event} e The event object
18319 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18321 onBeforeDrag : function(data, e){
18326 * An empty function by default, but provided so that you can perform a custom action once the initial
18327 * drag event has begun. The drag cannot be canceled from this function.
18328 * @param {Number} x The x position of the click on the dragged object
18329 * @param {Number} y The y position of the click on the dragged object
18331 onStartDrag : Roo.emptyFn,
18333 // private - YUI override
18334 startDrag : function(x, y){
18335 this.proxy.reset();
18336 this.dragging = true;
18337 this.proxy.update("");
18338 this.onInitDrag(x, y);
18343 onInitDrag : function(x, y){
18344 var clone = this.el.dom.cloneNode(true);
18345 clone.id = Roo.id(); // prevent duplicate ids
18346 this.proxy.update(clone);
18347 this.onStartDrag(x, y);
18352 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18353 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18355 getProxy : function(){
18360 * Hides the drag source's {@link Roo.dd.StatusProxy}
18362 hideProxy : function(){
18364 this.proxy.reset(true);
18365 this.dragging = false;
18369 triggerCacheRefresh : function(){
18370 Roo.dd.DDM.refreshCache(this.groups);
18373 // private - override to prevent hiding
18374 b4EndDrag: function(e) {
18377 // private - override to prevent moving
18378 endDrag : function(e){
18379 this.onEndDrag(this.dragData, e);
18383 onEndDrag : function(data, e){
18386 // private - pin to cursor
18387 autoOffset : function(x, y) {
18388 this.setDelta(-12, -20);
18392 * Ext JS Library 1.1.1
18393 * Copyright(c) 2006-2007, Ext JS, LLC.
18395 * Originally Released Under LGPL - original licence link has changed is not relivant.
18398 * <script type="text/javascript">
18403 * @class Roo.dd.DropTarget
18404 * @extends Roo.dd.DDTarget
18405 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18406 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18408 * @param {String/HTMLElement/Element} el The container element
18409 * @param {Object} config
18411 Roo.dd.DropTarget = function(el, config){
18412 this.el = Roo.get(el);
18414 var listeners = false; ;
18415 if (config && config.listeners) {
18416 listeners= config.listeners;
18417 delete config.listeners;
18419 Roo.apply(this, config);
18421 if(this.containerScroll){
18422 Roo.dd.ScrollManager.register(this.el);
18426 * @scope Roo.dd.DropTarget
18431 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18432 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18433 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18435 * IMPORTANT : it should set this.overClass and this.dropAllowed
18437 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18438 * @param {Event} e The event
18439 * @param {Object} data An object containing arbitrary data supplied by the drag source
18445 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18446 * This method will be called on every mouse movement while the drag source is over the drop target.
18447 * This default implementation simply returns the dropAllowed config value.
18449 * IMPORTANT : it should set this.dropAllowed
18451 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18452 * @param {Event} e The event
18453 * @param {Object} data An object containing arbitrary data supplied by the drag source
18459 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18460 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18461 * overClass (if any) from the drop element.
18462 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18463 * @param {Event} e The event
18464 * @param {Object} data An object containing arbitrary data supplied by the drag source
18470 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18471 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18472 * implementation that does something to process the drop event and returns true so that the drag source's
18473 * repair action does not run.
18475 * IMPORTANT : it should set this.success
18477 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18478 * @param {Event} e The event
18479 * @param {Object} data An object containing arbitrary data supplied by the drag source
18485 Roo.dd.DropTarget.superclass.constructor.call( this,
18487 this.ddGroup || this.group,
18490 listeners : listeners || {}
18498 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18500 * @cfg {String} overClass
18501 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18504 * @cfg {String} ddGroup
18505 * The drag drop group to handle drop events for
18509 * @cfg {String} dropAllowed
18510 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18512 dropAllowed : "x-dd-drop-ok",
18514 * @cfg {String} dropNotAllowed
18515 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18517 dropNotAllowed : "x-dd-drop-nodrop",
18519 * @cfg {boolean} success
18520 * set this after drop listener..
18524 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18525 * if the drop point is valid for over/enter..
18532 isNotifyTarget : true,
18537 notifyEnter : function(dd, e, data)
18540 this.fireEvent('enter', dd, e, data);
18541 if(this.overClass){
18542 this.el.addClass(this.overClass);
18544 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18545 this.valid ? this.dropAllowed : this.dropNotAllowed
18552 notifyOver : function(dd, e, data)
18555 this.fireEvent('over', dd, e, data);
18556 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18557 this.valid ? this.dropAllowed : this.dropNotAllowed
18564 notifyOut : function(dd, e, data)
18566 this.fireEvent('out', dd, e, data);
18567 if(this.overClass){
18568 this.el.removeClass(this.overClass);
18575 notifyDrop : function(dd, e, data)
18577 this.success = false;
18578 this.fireEvent('drop', dd, e, data);
18579 return this.success;
18583 * Ext JS Library 1.1.1
18584 * Copyright(c) 2006-2007, Ext JS, LLC.
18586 * Originally Released Under LGPL - original licence link has changed is not relivant.
18589 * <script type="text/javascript">
18594 * @class Roo.dd.DragZone
18595 * @extends Roo.dd.DragSource
18596 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18597 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18599 * @param {String/HTMLElement/Element} el The container element
18600 * @param {Object} config
18602 Roo.dd.DragZone = function(el, config){
18603 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18604 if(this.containerScroll){
18605 Roo.dd.ScrollManager.register(this.el);
18609 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18611 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18612 * for auto scrolling during drag operations.
18615 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18616 * method after a failed drop (defaults to "c3daf9" - light blue)
18620 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18621 * for a valid target to drag based on the mouse down. Override this method
18622 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18623 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18624 * @param {EventObject} e The mouse down event
18625 * @return {Object} The dragData
18627 getDragData : function(e){
18628 return Roo.dd.Registry.getHandleFromEvent(e);
18632 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18633 * this.dragData.ddel
18634 * @param {Number} x The x position of the click on the dragged object
18635 * @param {Number} y The y position of the click on the dragged object
18636 * @return {Boolean} true to continue the drag, false to cancel
18638 onInitDrag : function(x, y){
18639 this.proxy.update(this.dragData.ddel.cloneNode(true));
18640 this.onStartDrag(x, y);
18645 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18647 afterRepair : function(){
18649 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18651 this.dragging = false;
18655 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18656 * the XY of this.dragData.ddel
18657 * @param {EventObject} e The mouse up event
18658 * @return {Array} The xy location (e.g. [100, 200])
18660 getRepairXY : function(e){
18661 return Roo.Element.fly(this.dragData.ddel).getXY();
18665 * Ext JS Library 1.1.1
18666 * Copyright(c) 2006-2007, Ext JS, LLC.
18668 * Originally Released Under LGPL - original licence link has changed is not relivant.
18671 * <script type="text/javascript">
18674 * @class Roo.dd.DropZone
18675 * @extends Roo.dd.DropTarget
18676 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18677 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18679 * @param {String/HTMLElement/Element} el The container element
18680 * @param {Object} config
18682 Roo.dd.DropZone = function(el, config){
18683 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18686 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18688 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18689 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18690 * provide your own custom lookup.
18691 * @param {Event} e The event
18692 * @return {Object} data The custom data
18694 getTargetFromEvent : function(e){
18695 return Roo.dd.Registry.getTargetFromEvent(e);
18699 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18700 * that it has registered. This method has no default implementation and should be overridden to provide
18701 * node-specific processing if necessary.
18702 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18703 * {@link #getTargetFromEvent} for this node)
18704 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18705 * @param {Event} e The event
18706 * @param {Object} data An object containing arbitrary data supplied by the drag source
18708 onNodeEnter : function(n, dd, e, data){
18713 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18714 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18715 * overridden to provide the proper feedback.
18716 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18717 * {@link #getTargetFromEvent} for this node)
18718 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18719 * @param {Event} e The event
18720 * @param {Object} data An object containing arbitrary data supplied by the drag source
18721 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18722 * underlying {@link Roo.dd.StatusProxy} can be updated
18724 onNodeOver : function(n, dd, e, data){
18725 return this.dropAllowed;
18729 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18730 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18731 * node-specific processing if necessary.
18732 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18733 * {@link #getTargetFromEvent} for this node)
18734 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18735 * @param {Event} e The event
18736 * @param {Object} data An object containing arbitrary data supplied by the drag source
18738 onNodeOut : function(n, dd, e, data){
18743 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18744 * the drop node. The default implementation returns false, so it should be overridden to provide the
18745 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18746 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18747 * {@link #getTargetFromEvent} for this node)
18748 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18749 * @param {Event} e The event
18750 * @param {Object} data An object containing arbitrary data supplied by the drag source
18751 * @return {Boolean} True if the drop was valid, else false
18753 onNodeDrop : function(n, dd, e, data){
18758 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18759 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18760 * it should be overridden to provide the proper feedback if necessary.
18761 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18762 * @param {Event} e The event
18763 * @param {Object} data An object containing arbitrary data supplied by the drag source
18764 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18765 * underlying {@link Roo.dd.StatusProxy} can be updated
18767 onContainerOver : function(dd, e, data){
18768 return this.dropNotAllowed;
18772 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18773 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18774 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18775 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18776 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18777 * @param {Event} e The event
18778 * @param {Object} data An object containing arbitrary data supplied by the drag source
18779 * @return {Boolean} True if the drop was valid, else false
18781 onContainerDrop : function(dd, e, data){
18786 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18787 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18788 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18789 * you should override this method and provide a custom implementation.
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 notifyEnter : function(dd, e, data){
18797 return this.dropNotAllowed;
18801 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18802 * This method will be called on every mouse movement while the drag source is over the drop zone.
18803 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18804 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18805 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18806 * registered node, it will call {@link #onContainerOver}.
18807 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18808 * @param {Event} e The event
18809 * @param {Object} data An object containing arbitrary data supplied by the drag source
18810 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18811 * underlying {@link Roo.dd.StatusProxy} can be updated
18813 notifyOver : function(dd, e, data){
18814 var n = this.getTargetFromEvent(e);
18815 if(!n){ // not over valid drop target
18816 if(this.lastOverNode){
18817 this.onNodeOut(this.lastOverNode, dd, e, data);
18818 this.lastOverNode = null;
18820 return this.onContainerOver(dd, e, data);
18822 if(this.lastOverNode != n){
18823 if(this.lastOverNode){
18824 this.onNodeOut(this.lastOverNode, dd, e, data);
18826 this.onNodeEnter(n, dd, e, data);
18827 this.lastOverNode = n;
18829 return this.onNodeOver(n, dd, e, data);
18833 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18834 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18835 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18836 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18837 * @param {Event} e The event
18838 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18840 notifyOut : function(dd, e, data){
18841 if(this.lastOverNode){
18842 this.onNodeOut(this.lastOverNode, dd, e, data);
18843 this.lastOverNode = null;
18848 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18849 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18850 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18851 * otherwise it will call {@link #onContainerDrop}.
18852 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18853 * @param {Event} e The event
18854 * @param {Object} data An object containing arbitrary data supplied by the drag source
18855 * @return {Boolean} True if the drop was valid, else false
18857 notifyDrop : function(dd, e, data){
18858 if(this.lastOverNode){
18859 this.onNodeOut(this.lastOverNode, dd, e, data);
18860 this.lastOverNode = null;
18862 var n = this.getTargetFromEvent(e);
18864 this.onNodeDrop(n, dd, e, data) :
18865 this.onContainerDrop(dd, e, data);
18869 triggerCacheRefresh : function(){
18870 Roo.dd.DDM.refreshCache(this.groups);
18874 * Ext JS Library 1.1.1
18875 * Copyright(c) 2006-2007, Ext JS, LLC.
18877 * Originally Released Under LGPL - original licence link has changed is not relivant.
18880 * <script type="text/javascript">
18885 * @class Roo.data.SortTypes
18887 * Defines the default sorting (casting?) comparison functions used when sorting data.
18889 Roo.data.SortTypes = {
18891 * Default sort that does nothing
18892 * @param {Mixed} s The value being converted
18893 * @return {Mixed} The comparison value
18895 none : function(s){
18900 * The regular expression used to strip tags
18904 stripTagsRE : /<\/?[^>]+>/gi,
18907 * Strips all HTML tags to sort on text only
18908 * @param {Mixed} s The value being converted
18909 * @return {String} The comparison value
18911 asText : function(s){
18912 return String(s).replace(this.stripTagsRE, "");
18916 * Strips all HTML tags to sort on text only - Case insensitive
18917 * @param {Mixed} s The value being converted
18918 * @return {String} The comparison value
18920 asUCText : function(s){
18921 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18925 * Case insensitive string
18926 * @param {Mixed} s The value being converted
18927 * @return {String} The comparison value
18929 asUCString : function(s) {
18930 return String(s).toUpperCase();
18935 * @param {Mixed} s The value being converted
18936 * @return {Number} The comparison value
18938 asDate : function(s) {
18942 if(s instanceof Date){
18943 return s.getTime();
18945 return Date.parse(String(s));
18950 * @param {Mixed} s The value being converted
18951 * @return {Float} The comparison value
18953 asFloat : function(s) {
18954 var val = parseFloat(String(s).replace(/,/g, ""));
18955 if(isNaN(val)) val = 0;
18961 * @param {Mixed} s The value being converted
18962 * @return {Number} The comparison value
18964 asInt : function(s) {
18965 var val = parseInt(String(s).replace(/,/g, ""));
18966 if(isNaN(val)) val = 0;
18971 * Ext JS Library 1.1.1
18972 * Copyright(c) 2006-2007, Ext JS, LLC.
18974 * Originally Released Under LGPL - original licence link has changed is not relivant.
18977 * <script type="text/javascript">
18981 * @class Roo.data.Record
18982 * Instances of this class encapsulate both record <em>definition</em> information, and record
18983 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18984 * to access Records cached in an {@link Roo.data.Store} object.<br>
18986 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18987 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18990 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18992 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18993 * {@link #create}. The parameters are the same.
18994 * @param {Array} data An associative Array of data values keyed by the field name.
18995 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18996 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18997 * not specified an integer id is generated.
18999 Roo.data.Record = function(data, id){
19000 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19005 * Generate a constructor for a specific record layout.
19006 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19007 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19008 * Each field definition object may contain the following properties: <ul>
19009 * <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,
19010 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19011 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19012 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19013 * is being used, then this is a string containing the javascript expression to reference the data relative to
19014 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19015 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19016 * this may be omitted.</p></li>
19017 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19018 * <ul><li>auto (Default, implies no conversion)</li>
19023 * <li>date</li></ul></p></li>
19024 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19025 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19026 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19027 * by the Reader into an object that will be stored in the Record. It is passed the
19028 * following parameters:<ul>
19029 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19031 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19033 * <br>usage:<br><pre><code>
19034 var TopicRecord = Roo.data.Record.create(
19035 {name: 'title', mapping: 'topic_title'},
19036 {name: 'author', mapping: 'username'},
19037 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19038 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19039 {name: 'lastPoster', mapping: 'user2'},
19040 {name: 'excerpt', mapping: 'post_text'}
19043 var myNewRecord = new TopicRecord({
19044 title: 'Do my job please',
19047 lastPost: new Date(),
19048 lastPoster: 'Animal',
19049 excerpt: 'No way dude!'
19051 myStore.add(myNewRecord);
19056 Roo.data.Record.create = function(o){
19057 var f = function(){
19058 f.superclass.constructor.apply(this, arguments);
19060 Roo.extend(f, Roo.data.Record);
19061 var p = f.prototype;
19062 p.fields = new Roo.util.MixedCollection(false, function(field){
19065 for(var i = 0, len = o.length; i < len; i++){
19066 p.fields.add(new Roo.data.Field(o[i]));
19068 f.getField = function(name){
19069 return p.fields.get(name);
19074 Roo.data.Record.AUTO_ID = 1000;
19075 Roo.data.Record.EDIT = 'edit';
19076 Roo.data.Record.REJECT = 'reject';
19077 Roo.data.Record.COMMIT = 'commit';
19079 Roo.data.Record.prototype = {
19081 * Readonly flag - true if this record has been modified.
19090 join : function(store){
19091 this.store = store;
19095 * Set the named field to the specified value.
19096 * @param {String} name The name of the field to set.
19097 * @param {Object} value The value to set the field to.
19099 set : function(name, value){
19100 if(this.data[name] == value){
19104 if(!this.modified){
19105 this.modified = {};
19107 if(typeof this.modified[name] == 'undefined'){
19108 this.modified[name] = this.data[name];
19110 this.data[name] = value;
19111 if(!this.editing && this.store){
19112 this.store.afterEdit(this);
19117 * Get the value of the named field.
19118 * @param {String} name The name of the field to get the value of.
19119 * @return {Object} The value of the field.
19121 get : function(name){
19122 return this.data[name];
19126 beginEdit : function(){
19127 this.editing = true;
19128 this.modified = {};
19132 cancelEdit : function(){
19133 this.editing = false;
19134 delete this.modified;
19138 endEdit : function(){
19139 this.editing = false;
19140 if(this.dirty && this.store){
19141 this.store.afterEdit(this);
19146 * Usually called by the {@link Roo.data.Store} which owns the Record.
19147 * Rejects all changes made to the Record since either creation, or the last commit operation.
19148 * Modified fields are reverted to their original values.
19150 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19151 * of reject operations.
19153 reject : function(){
19154 var m = this.modified;
19156 if(typeof m[n] != "function"){
19157 this.data[n] = m[n];
19160 this.dirty = false;
19161 delete this.modified;
19162 this.editing = false;
19164 this.store.afterReject(this);
19169 * Usually called by the {@link Roo.data.Store} which owns the Record.
19170 * Commits all changes made to the Record since either creation, or the last commit operation.
19172 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19173 * of commit operations.
19175 commit : function(){
19176 this.dirty = false;
19177 delete this.modified;
19178 this.editing = false;
19180 this.store.afterCommit(this);
19185 hasError : function(){
19186 return this.error != null;
19190 clearError : function(){
19195 * Creates a copy of this record.
19196 * @param {String} id (optional) A new record id if you don't want to use this record's id
19199 copy : function(newId) {
19200 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19204 * Ext JS Library 1.1.1
19205 * Copyright(c) 2006-2007, Ext JS, LLC.
19207 * Originally Released Under LGPL - original licence link has changed is not relivant.
19210 * <script type="text/javascript">
19216 * @class Roo.data.Store
19217 * @extends Roo.util.Observable
19218 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19219 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19221 * 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
19222 * has no knowledge of the format of the data returned by the Proxy.<br>
19224 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19225 * instances from the data object. These records are cached and made available through accessor functions.
19227 * Creates a new Store.
19228 * @param {Object} config A config object containing the objects needed for the Store to access data,
19229 * and read the data into Records.
19231 Roo.data.Store = function(config){
19232 this.data = new Roo.util.MixedCollection(false);
19233 this.data.getKey = function(o){
19236 this.baseParams = {};
19238 this.paramNames = {
19243 "multisort" : "_multisort"
19246 if(config && config.data){
19247 this.inlineData = config.data;
19248 delete config.data;
19251 Roo.apply(this, config);
19253 if(this.reader){ // reader passed
19254 this.reader = Roo.factory(this.reader, Roo.data);
19255 this.reader.xmodule = this.xmodule || false;
19256 if(!this.recordType){
19257 this.recordType = this.reader.recordType;
19259 if(this.reader.onMetaChange){
19260 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19264 if(this.recordType){
19265 this.fields = this.recordType.prototype.fields;
19267 this.modified = [];
19271 * @event datachanged
19272 * Fires when the data cache has changed, and a widget which is using this Store
19273 * as a Record cache should refresh its view.
19274 * @param {Store} this
19276 datachanged : true,
19278 * @event metachange
19279 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19280 * @param {Store} this
19281 * @param {Object} meta The JSON metadata
19286 * Fires when Records have been added to the Store
19287 * @param {Store} this
19288 * @param {Roo.data.Record[]} records The array of Records added
19289 * @param {Number} index The index at which the record(s) were added
19294 * Fires when a Record has been removed from the Store
19295 * @param {Store} this
19296 * @param {Roo.data.Record} record The Record that was removed
19297 * @param {Number} index The index at which the record was removed
19302 * Fires when a Record has been updated
19303 * @param {Store} this
19304 * @param {Roo.data.Record} record The Record that was updated
19305 * @param {String} operation The update operation being performed. Value may be one of:
19307 Roo.data.Record.EDIT
19308 Roo.data.Record.REJECT
19309 Roo.data.Record.COMMIT
19315 * Fires when the data cache has been cleared.
19316 * @param {Store} this
19320 * @event beforeload
19321 * Fires before a request is made for a new data object. If the beforeload handler returns false
19322 * the load action will be canceled.
19323 * @param {Store} this
19324 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19329 * Fires after a new set of Records has been loaded.
19330 * @param {Store} this
19331 * @param {Roo.data.Record[]} records The Records that were loaded
19332 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19336 * @event loadexception
19337 * Fires if an exception occurs in the Proxy during loading.
19338 * Called with the signature of the Proxy's "loadexception" event.
19339 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19342 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19343 * @param {Object} load options
19344 * @param {Object} jsonData from your request (normally this contains the Exception)
19346 loadexception : true
19350 this.proxy = Roo.factory(this.proxy, Roo.data);
19351 this.proxy.xmodule = this.xmodule || false;
19352 this.relayEvents(this.proxy, ["loadexception"]);
19354 this.sortToggle = {};
19355 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19357 Roo.data.Store.superclass.constructor.call(this);
19359 if(this.inlineData){
19360 this.loadData(this.inlineData);
19361 delete this.inlineData;
19364 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19366 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19367 * without a remote query - used by combo/forms at present.
19371 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19374 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19377 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19378 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19381 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19382 * on any HTTP request
19385 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19388 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19392 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19393 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19395 remoteSort : false,
19398 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19399 * loaded or when a record is removed. (defaults to false).
19401 pruneModifiedRecords : false,
19404 lastOptions : null,
19407 * Add Records to the Store and fires the add event.
19408 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19410 add : function(records){
19411 records = [].concat(records);
19412 for(var i = 0, len = records.length; i < len; i++){
19413 records[i].join(this);
19415 var index = this.data.length;
19416 this.data.addAll(records);
19417 this.fireEvent("add", this, records, index);
19421 * Remove a Record from the Store and fires the remove event.
19422 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19424 remove : function(record){
19425 var index = this.data.indexOf(record);
19426 this.data.removeAt(index);
19427 if(this.pruneModifiedRecords){
19428 this.modified.remove(record);
19430 this.fireEvent("remove", this, record, index);
19434 * Remove all Records from the Store and fires the clear event.
19436 removeAll : function(){
19438 if(this.pruneModifiedRecords){
19439 this.modified = [];
19441 this.fireEvent("clear", this);
19445 * Inserts Records to the Store at the given index and fires the add event.
19446 * @param {Number} index The start index at which to insert the passed Records.
19447 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19449 insert : function(index, records){
19450 records = [].concat(records);
19451 for(var i = 0, len = records.length; i < len; i++){
19452 this.data.insert(index, records[i]);
19453 records[i].join(this);
19455 this.fireEvent("add", this, records, index);
19459 * Get the index within the cache of the passed Record.
19460 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19461 * @return {Number} The index of the passed Record. Returns -1 if not found.
19463 indexOf : function(record){
19464 return this.data.indexOf(record);
19468 * Get the index within the cache of the Record with the passed id.
19469 * @param {String} id The id of the Record to find.
19470 * @return {Number} The index of the Record. Returns -1 if not found.
19472 indexOfId : function(id){
19473 return this.data.indexOfKey(id);
19477 * Get the Record with the specified id.
19478 * @param {String} id The id of the Record to find.
19479 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19481 getById : function(id){
19482 return this.data.key(id);
19486 * Get the Record at the specified index.
19487 * @param {Number} index The index of the Record to find.
19488 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19490 getAt : function(index){
19491 return this.data.itemAt(index);
19495 * Returns a range of Records between specified indices.
19496 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19497 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19498 * @return {Roo.data.Record[]} An array of Records
19500 getRange : function(start, end){
19501 return this.data.getRange(start, end);
19505 storeOptions : function(o){
19506 o = Roo.apply({}, o);
19509 this.lastOptions = o;
19513 * Loads the Record cache from the configured Proxy using the configured Reader.
19515 * If using remote paging, then the first load call must specify the <em>start</em>
19516 * and <em>limit</em> properties in the options.params property to establish the initial
19517 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19519 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19520 * and this call will return before the new data has been loaded. Perform any post-processing
19521 * in a callback function, or in a "load" event handler.</strong>
19523 * @param {Object} options An object containing properties which control loading options:<ul>
19524 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19525 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19526 * passed the following arguments:<ul>
19527 * <li>r : Roo.data.Record[]</li>
19528 * <li>options: Options object from the load call</li>
19529 * <li>success: Boolean success indicator</li></ul></li>
19530 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19531 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19534 load : function(options){
19535 options = options || {};
19536 if(this.fireEvent("beforeload", this, options) !== false){
19537 this.storeOptions(options);
19538 var p = Roo.apply(options.params || {}, this.baseParams);
19539 // if meta was not loaded from remote source.. try requesting it.
19540 if (!this.reader.metaFromRemote) {
19541 p._requestMeta = 1;
19543 if(this.sortInfo && this.remoteSort){
19544 var pn = this.paramNames;
19545 p[pn["sort"]] = this.sortInfo.field;
19546 p[pn["dir"]] = this.sortInfo.direction;
19548 if (this.multiSort) {
19549 var pn = this.paramNames;
19550 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19553 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19558 * Reloads the Record cache from the configured Proxy using the configured Reader and
19559 * the options from the last load operation performed.
19560 * @param {Object} options (optional) An object containing properties which may override the options
19561 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19562 * the most recently used options are reused).
19564 reload : function(options){
19565 this.load(Roo.applyIf(options||{}, this.lastOptions));
19569 // Called as a callback by the Reader during a load operation.
19570 loadRecords : function(o, options, success){
19571 if(!o || success === false){
19572 if(success !== false){
19573 this.fireEvent("load", this, [], options);
19575 if(options.callback){
19576 options.callback.call(options.scope || this, [], options, false);
19580 // if data returned failure - throw an exception.
19581 if (o.success === false) {
19582 // show a message if no listener is registered.
19583 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
19584 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
19586 // loadmask wil be hooked into this..
19587 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19590 var r = o.records, t = o.totalRecords || r.length;
19591 if(!options || options.add !== true){
19592 if(this.pruneModifiedRecords){
19593 this.modified = [];
19595 for(var i = 0, len = r.length; i < len; i++){
19599 this.data = this.snapshot;
19600 delete this.snapshot;
19603 this.data.addAll(r);
19604 this.totalLength = t;
19606 this.fireEvent("datachanged", this);
19608 this.totalLength = Math.max(t, this.data.length+r.length);
19611 this.fireEvent("load", this, r, options);
19612 if(options.callback){
19613 options.callback.call(options.scope || this, r, options, true);
19619 * Loads data from a passed data block. A Reader which understands the format of the data
19620 * must have been configured in the constructor.
19621 * @param {Object} data The data block from which to read the Records. The format of the data expected
19622 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19623 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19625 loadData : function(o, append){
19626 var r = this.reader.readRecords(o);
19627 this.loadRecords(r, {add: append}, true);
19631 * Gets the number of cached records.
19633 * <em>If using paging, this may not be the total size of the dataset. If the data object
19634 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19635 * the data set size</em>
19637 getCount : function(){
19638 return this.data.length || 0;
19642 * Gets the total number of records in the dataset as returned by the server.
19644 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19645 * the dataset size</em>
19647 getTotalCount : function(){
19648 return this.totalLength || 0;
19652 * Returns the sort state of the Store as an object with two properties:
19654 field {String} The name of the field by which the Records are sorted
19655 direction {String} The sort order, "ASC" or "DESC"
19658 getSortState : function(){
19659 return this.sortInfo;
19663 applySort : function(){
19664 if(this.sortInfo && !this.remoteSort){
19665 var s = this.sortInfo, f = s.field;
19666 var st = this.fields.get(f).sortType;
19667 var fn = function(r1, r2){
19668 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19669 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19671 this.data.sort(s.direction, fn);
19672 if(this.snapshot && this.snapshot != this.data){
19673 this.snapshot.sort(s.direction, fn);
19679 * Sets the default sort column and order to be used by the next load operation.
19680 * @param {String} fieldName The name of the field to sort by.
19681 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19683 setDefaultSort : function(field, dir){
19684 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19688 * Sort the Records.
19689 * If remote sorting is used, the sort is performed on the server, and the cache is
19690 * reloaded. If local sorting is used, the cache is sorted internally.
19691 * @param {String} fieldName The name of the field to sort by.
19692 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19694 sort : function(fieldName, dir){
19695 var f = this.fields.get(fieldName);
19697 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19699 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19700 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19705 this.sortToggle[f.name] = dir;
19706 this.sortInfo = {field: f.name, direction: dir};
19707 if(!this.remoteSort){
19709 this.fireEvent("datachanged", this);
19711 this.load(this.lastOptions);
19716 * Calls the specified function for each of the Records in the cache.
19717 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19718 * Returning <em>false</em> aborts and exits the iteration.
19719 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19721 each : function(fn, scope){
19722 this.data.each(fn, scope);
19726 * Gets all records modified since the last commit. Modified records are persisted across load operations
19727 * (e.g., during paging).
19728 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19730 getModifiedRecords : function(){
19731 return this.modified;
19735 createFilterFn : function(property, value, anyMatch){
19736 if(!value.exec){ // not a regex
19737 value = String(value);
19738 if(value.length == 0){
19741 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19743 return function(r){
19744 return value.test(r.data[property]);
19749 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19750 * @param {String} property A field on your records
19751 * @param {Number} start The record index to start at (defaults to 0)
19752 * @param {Number} end The last record index to include (defaults to length - 1)
19753 * @return {Number} The sum
19755 sum : function(property, start, end){
19756 var rs = this.data.items, v = 0;
19757 start = start || 0;
19758 end = (end || end === 0) ? end : rs.length-1;
19760 for(var i = start; i <= end; i++){
19761 v += (rs[i].data[property] || 0);
19767 * Filter the records by a specified property.
19768 * @param {String} field A field on your records
19769 * @param {String/RegExp} value Either a string that the field
19770 * should start with or a RegExp to test against the field
19771 * @param {Boolean} anyMatch True to match any part not just the beginning
19773 filter : function(property, value, anyMatch){
19774 var fn = this.createFilterFn(property, value, anyMatch);
19775 return fn ? this.filterBy(fn) : this.clearFilter();
19779 * Filter by a function. The specified function will be called with each
19780 * record in this data source. If the function returns true the record is included,
19781 * otherwise it is filtered.
19782 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19783 * @param {Object} scope (optional) The scope of the function (defaults to this)
19785 filterBy : function(fn, scope){
19786 this.snapshot = this.snapshot || this.data;
19787 this.data = this.queryBy(fn, scope||this);
19788 this.fireEvent("datachanged", this);
19792 * Query the records by a specified property.
19793 * @param {String} field A field on your records
19794 * @param {String/RegExp} value Either a string that the field
19795 * should start with or a RegExp to test against the field
19796 * @param {Boolean} anyMatch True to match any part not just the beginning
19797 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19799 query : function(property, value, anyMatch){
19800 var fn = this.createFilterFn(property, value, anyMatch);
19801 return fn ? this.queryBy(fn) : this.data.clone();
19805 * Query by a function. The specified function will be called with each
19806 * record in this data source. If the function returns true the record is included
19808 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19809 * @param {Object} scope (optional) The scope of the function (defaults to this)
19810 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19812 queryBy : function(fn, scope){
19813 var data = this.snapshot || this.data;
19814 return data.filterBy(fn, scope||this);
19818 * Collects unique values for a particular dataIndex from this store.
19819 * @param {String} dataIndex The property to collect
19820 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19821 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19822 * @return {Array} An array of the unique values
19824 collect : function(dataIndex, allowNull, bypassFilter){
19825 var d = (bypassFilter === true && this.snapshot) ?
19826 this.snapshot.items : this.data.items;
19827 var v, sv, r = [], l = {};
19828 for(var i = 0, len = d.length; i < len; i++){
19829 v = d[i].data[dataIndex];
19831 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19840 * Revert to a view of the Record cache with no filtering applied.
19841 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19843 clearFilter : function(suppressEvent){
19844 if(this.snapshot && this.snapshot != this.data){
19845 this.data = this.snapshot;
19846 delete this.snapshot;
19847 if(suppressEvent !== true){
19848 this.fireEvent("datachanged", this);
19854 afterEdit : function(record){
19855 if(this.modified.indexOf(record) == -1){
19856 this.modified.push(record);
19858 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19862 afterReject : function(record){
19863 this.modified.remove(record);
19864 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19868 afterCommit : function(record){
19869 this.modified.remove(record);
19870 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19874 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19875 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19877 commitChanges : function(){
19878 var m = this.modified.slice(0);
19879 this.modified = [];
19880 for(var i = 0, len = m.length; i < len; i++){
19886 * Cancel outstanding changes on all changed records.
19888 rejectChanges : function(){
19889 var m = this.modified.slice(0);
19890 this.modified = [];
19891 for(var i = 0, len = m.length; i < len; i++){
19896 onMetaChange : function(meta, rtype, o){
19897 this.recordType = rtype;
19898 this.fields = rtype.prototype.fields;
19899 delete this.snapshot;
19900 this.sortInfo = meta.sortInfo || this.sortInfo;
19901 this.modified = [];
19902 this.fireEvent('metachange', this, this.reader.meta);
19906 * Ext JS Library 1.1.1
19907 * Copyright(c) 2006-2007, Ext JS, LLC.
19909 * Originally Released Under LGPL - original licence link has changed is not relivant.
19912 * <script type="text/javascript">
19916 * @class Roo.data.SimpleStore
19917 * @extends Roo.data.Store
19918 * Small helper class to make creating Stores from Array data easier.
19919 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19920 * @cfg {Array} fields An array of field definition objects, or field name strings.
19921 * @cfg {Array} data The multi-dimensional array of data
19923 * @param {Object} config
19925 Roo.data.SimpleStore = function(config){
19926 Roo.data.SimpleStore.superclass.constructor.call(this, {
19928 reader: new Roo.data.ArrayReader({
19931 Roo.data.Record.create(config.fields)
19933 proxy : new Roo.data.MemoryProxy(config.data)
19937 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19939 * Ext JS Library 1.1.1
19940 * Copyright(c) 2006-2007, Ext JS, LLC.
19942 * Originally Released Under LGPL - original licence link has changed is not relivant.
19945 * <script type="text/javascript">
19950 * @extends Roo.data.Store
19951 * @class Roo.data.JsonStore
19952 * Small helper class to make creating Stores for JSON data easier. <br/>
19954 var store = new Roo.data.JsonStore({
19955 url: 'get-images.php',
19957 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19960 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19961 * JsonReader and HttpProxy (unless inline data is provided).</b>
19962 * @cfg {Array} fields An array of field definition objects, or field name strings.
19964 * @param {Object} config
19966 Roo.data.JsonStore = function(c){
19967 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19968 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19969 reader: new Roo.data.JsonReader(c, c.fields)
19972 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19974 * Ext JS Library 1.1.1
19975 * Copyright(c) 2006-2007, Ext JS, LLC.
19977 * Originally Released Under LGPL - original licence link has changed is not relivant.
19980 * <script type="text/javascript">
19984 Roo.data.Field = function(config){
19985 if(typeof config == "string"){
19986 config = {name: config};
19988 Roo.apply(this, config);
19991 this.type = "auto";
19994 var st = Roo.data.SortTypes;
19995 // named sortTypes are supported, here we look them up
19996 if(typeof this.sortType == "string"){
19997 this.sortType = st[this.sortType];
20000 // set default sortType for strings and dates
20001 if(!this.sortType){
20004 this.sortType = st.asUCString;
20007 this.sortType = st.asDate;
20010 this.sortType = st.none;
20015 var stripRe = /[\$,%]/g;
20017 // prebuilt conversion function for this field, instead of
20018 // switching every time we're reading a value
20020 var cv, dateFormat = this.dateFormat;
20025 cv = function(v){ return v; };
20028 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20032 return v !== undefined && v !== null && v !== '' ?
20033 parseInt(String(v).replace(stripRe, ""), 10) : '';
20038 return v !== undefined && v !== null && v !== '' ?
20039 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20044 cv = function(v){ return v === true || v === "true" || v == 1; };
20051 if(v instanceof Date){
20055 if(dateFormat == "timestamp"){
20056 return new Date(v*1000);
20058 return Date.parseDate(v, dateFormat);
20060 var parsed = Date.parse(v);
20061 return parsed ? new Date(parsed) : null;
20070 Roo.data.Field.prototype = {
20078 * Ext JS Library 1.1.1
20079 * Copyright(c) 2006-2007, Ext JS, LLC.
20081 * Originally Released Under LGPL - original licence link has changed is not relivant.
20084 * <script type="text/javascript">
20087 // Base class for reading structured data from a data source. This class is intended to be
20088 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20091 * @class Roo.data.DataReader
20092 * Base class for reading structured data from a data source. This class is intended to be
20093 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20096 Roo.data.DataReader = function(meta, recordType){
20100 this.recordType = recordType instanceof Array ?
20101 Roo.data.Record.create(recordType) : recordType;
20104 Roo.data.DataReader.prototype = {
20106 * Create an empty record
20107 * @param {Object} data (optional) - overlay some values
20108 * @return {Roo.data.Record} record created.
20110 newRow : function(d) {
20112 this.recordType.prototype.fields.each(function(c) {
20114 case 'int' : da[c.name] = 0; break;
20115 case 'date' : da[c.name] = new Date(); break;
20116 case 'float' : da[c.name] = 0.0; break;
20117 case 'boolean' : da[c.name] = false; break;
20118 default : da[c.name] = ""; break;
20122 return new this.recordType(Roo.apply(da, d));
20127 * Ext JS Library 1.1.1
20128 * Copyright(c) 2006-2007, Ext JS, LLC.
20130 * Originally Released Under LGPL - original licence link has changed is not relivant.
20133 * <script type="text/javascript">
20137 * @class Roo.data.DataProxy
20138 * @extends Roo.data.Observable
20139 * This class is an abstract base class for implementations which provide retrieval of
20140 * unformatted data objects.<br>
20142 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20143 * (of the appropriate type which knows how to parse the data object) to provide a block of
20144 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20146 * Custom implementations must implement the load method as described in
20147 * {@link Roo.data.HttpProxy#load}.
20149 Roo.data.DataProxy = function(){
20152 * @event beforeload
20153 * Fires before a network request is made to retrieve a data object.
20154 * @param {Object} This DataProxy object.
20155 * @param {Object} params The params parameter to the load function.
20160 * Fires before the load method's callback is called.
20161 * @param {Object} This DataProxy object.
20162 * @param {Object} o The data object.
20163 * @param {Object} arg The callback argument object passed to the load function.
20167 * @event loadexception
20168 * Fires if an Exception occurs during data retrieval.
20169 * @param {Object} This DataProxy object.
20170 * @param {Object} o The data object.
20171 * @param {Object} arg The callback argument object passed to the load function.
20172 * @param {Object} e The Exception.
20174 loadexception : true
20176 Roo.data.DataProxy.superclass.constructor.call(this);
20179 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20182 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20186 * Ext JS Library 1.1.1
20187 * Copyright(c) 2006-2007, Ext JS, LLC.
20189 * Originally Released Under LGPL - original licence link has changed is not relivant.
20192 * <script type="text/javascript">
20195 * @class Roo.data.MemoryProxy
20196 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20197 * to the Reader when its load method is called.
20199 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20201 Roo.data.MemoryProxy = function(data){
20205 Roo.data.MemoryProxy.superclass.constructor.call(this);
20209 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20211 * Load data from the requested source (in this case an in-memory
20212 * data object passed to the constructor), read the data object into
20213 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20214 * process that block using the passed callback.
20215 * @param {Object} params This parameter is not used by the MemoryProxy class.
20216 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20217 * object into a block of Roo.data.Records.
20218 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20219 * The function must be passed <ul>
20220 * <li>The Record block object</li>
20221 * <li>The "arg" argument from the load function</li>
20222 * <li>A boolean success indicator</li>
20224 * @param {Object} scope The scope in which to call the callback
20225 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20227 load : function(params, reader, callback, scope, arg){
20228 params = params || {};
20231 result = reader.readRecords(this.data);
20233 this.fireEvent("loadexception", this, arg, null, e);
20234 callback.call(scope, null, arg, false);
20237 callback.call(scope, result, arg, true);
20241 update : function(params, records){
20246 * Ext JS Library 1.1.1
20247 * Copyright(c) 2006-2007, Ext JS, LLC.
20249 * Originally Released Under LGPL - original licence link has changed is not relivant.
20252 * <script type="text/javascript">
20255 * @class Roo.data.HttpProxy
20256 * @extends Roo.data.DataProxy
20257 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20258 * configured to reference a certain URL.<br><br>
20260 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20261 * from which the running page was served.<br><br>
20263 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20265 * Be aware that to enable the browser to parse an XML document, the server must set
20266 * the Content-Type header in the HTTP response to "text/xml".
20268 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20269 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20270 * will be used to make the request.
20272 Roo.data.HttpProxy = function(conn){
20273 Roo.data.HttpProxy.superclass.constructor.call(this);
20274 // is conn a conn config or a real conn?
20276 this.useAjax = !conn || !conn.events;
20280 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20281 // thse are take from connection...
20284 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20287 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20288 * extra parameters to each request made by this object. (defaults to undefined)
20291 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20292 * to each request made by this object. (defaults to undefined)
20295 * @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)
20298 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20301 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20307 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20311 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20312 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20313 * a finer-grained basis than the DataProxy events.
20315 getConnection : function(){
20316 return this.useAjax ? Roo.Ajax : this.conn;
20320 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20321 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20322 * process that block using the passed callback.
20323 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20324 * for the request to the remote server.
20325 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20326 * object into a block of Roo.data.Records.
20327 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20328 * The function must be passed <ul>
20329 * <li>The Record block object</li>
20330 * <li>The "arg" argument from the load function</li>
20331 * <li>A boolean success indicator</li>
20333 * @param {Object} scope The scope in which to call the callback
20334 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20336 load : function(params, reader, callback, scope, arg){
20337 if(this.fireEvent("beforeload", this, params) !== false){
20339 params : params || {},
20341 callback : callback,
20346 callback : this.loadResponse,
20350 Roo.applyIf(o, this.conn);
20351 if(this.activeRequest){
20352 Roo.Ajax.abort(this.activeRequest);
20354 this.activeRequest = Roo.Ajax.request(o);
20356 this.conn.request(o);
20359 callback.call(scope||this, null, arg, false);
20364 loadResponse : function(o, success, response){
20365 delete this.activeRequest;
20367 this.fireEvent("loadexception", this, o, response);
20368 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20373 result = o.reader.read(response);
20375 this.fireEvent("loadexception", this, o, response, e);
20376 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20380 this.fireEvent("load", this, o, o.request.arg);
20381 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20385 update : function(dataSet){
20390 updateResponse : function(dataSet){
20395 * Ext JS Library 1.1.1
20396 * Copyright(c) 2006-2007, Ext JS, LLC.
20398 * Originally Released Under LGPL - original licence link has changed is not relivant.
20401 * <script type="text/javascript">
20405 * @class Roo.data.ScriptTagProxy
20406 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20407 * other than the originating domain of the running page.<br><br>
20409 * <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
20410 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20412 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20413 * source code that is used as the source inside a <script> tag.<br><br>
20415 * In order for the browser to process the returned data, the server must wrap the data object
20416 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20417 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20418 * depending on whether the callback name was passed:
20421 boolean scriptTag = false;
20422 String cb = request.getParameter("callback");
20425 response.setContentType("text/javascript");
20427 response.setContentType("application/x-json");
20429 Writer out = response.getWriter();
20431 out.write(cb + "(");
20433 out.print(dataBlock.toJsonString());
20440 * @param {Object} config A configuration object.
20442 Roo.data.ScriptTagProxy = function(config){
20443 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20444 Roo.apply(this, config);
20445 this.head = document.getElementsByTagName("head")[0];
20448 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20450 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20452 * @cfg {String} url The URL from which to request the data object.
20455 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20459 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20460 * the server the name of the callback function set up by the load call to process the returned data object.
20461 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20462 * javascript output which calls this named function passing the data object as its only parameter.
20464 callbackParam : "callback",
20466 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20467 * name to the request.
20472 * Load data from the configured URL, read the data object into
20473 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20474 * process that block using the passed callback.
20475 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20476 * for the request to the remote server.
20477 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20478 * object into a block of Roo.data.Records.
20479 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20480 * The function must be passed <ul>
20481 * <li>The Record block object</li>
20482 * <li>The "arg" argument from the load function</li>
20483 * <li>A boolean success indicator</li>
20485 * @param {Object} scope The scope in which to call the callback
20486 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20488 load : function(params, reader, callback, scope, arg){
20489 if(this.fireEvent("beforeload", this, params) !== false){
20491 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20493 var url = this.url;
20494 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20496 url += "&_dc=" + (new Date().getTime());
20498 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20501 cb : "stcCallback"+transId,
20502 scriptId : "stcScript"+transId,
20506 callback : callback,
20512 window[trans.cb] = function(o){
20513 conn.handleResponse(o, trans);
20516 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20518 if(this.autoAbort !== false){
20522 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20524 var script = document.createElement("script");
20525 script.setAttribute("src", url);
20526 script.setAttribute("type", "text/javascript");
20527 script.setAttribute("id", trans.scriptId);
20528 this.head.appendChild(script);
20530 this.trans = trans;
20532 callback.call(scope||this, null, arg, false);
20537 isLoading : function(){
20538 return this.trans ? true : false;
20542 * Abort the current server request.
20544 abort : function(){
20545 if(this.isLoading()){
20546 this.destroyTrans(this.trans);
20551 destroyTrans : function(trans, isLoaded){
20552 this.head.removeChild(document.getElementById(trans.scriptId));
20553 clearTimeout(trans.timeoutId);
20555 window[trans.cb] = undefined;
20557 delete window[trans.cb];
20560 // if hasn't been loaded, wait for load to remove it to prevent script error
20561 window[trans.cb] = function(){
20562 window[trans.cb] = undefined;
20564 delete window[trans.cb];
20571 handleResponse : function(o, trans){
20572 this.trans = false;
20573 this.destroyTrans(trans, true);
20576 result = trans.reader.readRecords(o);
20578 this.fireEvent("loadexception", this, o, trans.arg, e);
20579 trans.callback.call(trans.scope||window, null, trans.arg, false);
20582 this.fireEvent("load", this, o, trans.arg);
20583 trans.callback.call(trans.scope||window, result, trans.arg, true);
20587 handleFailure : function(trans){
20588 this.trans = false;
20589 this.destroyTrans(trans, false);
20590 this.fireEvent("loadexception", this, null, trans.arg);
20591 trans.callback.call(trans.scope||window, null, trans.arg, false);
20595 * Ext JS Library 1.1.1
20596 * Copyright(c) 2006-2007, Ext JS, LLC.
20598 * Originally Released Under LGPL - original licence link has changed is not relivant.
20601 * <script type="text/javascript">
20605 * @class Roo.data.JsonReader
20606 * @extends Roo.data.DataReader
20607 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20608 * based on mappings in a provided Roo.data.Record constructor.
20610 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20611 * in the reply previously.
20616 var RecordDef = Roo.data.Record.create([
20617 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20618 {name: 'occupation'} // This field will use "occupation" as the mapping.
20620 var myReader = new Roo.data.JsonReader({
20621 totalProperty: "results", // The property which contains the total dataset size (optional)
20622 root: "rows", // The property which contains an Array of row objects
20623 id: "id" // The property within each row object that provides an ID for the record (optional)
20627 * This would consume a JSON file like this:
20629 { 'results': 2, 'rows': [
20630 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20631 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20634 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20635 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20636 * paged from the remote server.
20637 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20638 * @cfg {String} root name of the property which contains the Array of row objects.
20639 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20641 * Create a new JsonReader
20642 * @param {Object} meta Metadata configuration options
20643 * @param {Object} recordType Either an Array of field definition objects,
20644 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20646 Roo.data.JsonReader = function(meta, recordType){
20649 // set some defaults:
20650 Roo.applyIf(meta, {
20651 totalProperty: 'total',
20652 successProperty : 'success',
20657 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20659 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20662 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20663 * Used by Store query builder to append _requestMeta to params.
20666 metaFromRemote : false,
20668 * This method is only used by a DataProxy which has retrieved data from a remote server.
20669 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20670 * @return {Object} data A data block which is used by an Roo.data.Store object as
20671 * a cache of Roo.data.Records.
20673 read : function(response){
20674 var json = response.responseText;
20676 var o = /* eval:var:o */ eval("("+json+")");
20678 throw {message: "JsonReader.read: Json object not found"};
20684 this.metaFromRemote = true;
20685 this.meta = o.metaData;
20686 this.recordType = Roo.data.Record.create(o.metaData.fields);
20687 this.onMetaChange(this.meta, this.recordType, o);
20689 return this.readRecords(o);
20692 // private function a store will implement
20693 onMetaChange : function(meta, recordType, o){
20700 simpleAccess: function(obj, subsc) {
20707 getJsonAccessor: function(){
20709 return function(expr) {
20711 return(re.test(expr))
20712 ? new Function("obj", "return obj." + expr)
20717 return Roo.emptyFn;
20722 * Create a data block containing Roo.data.Records from an XML document.
20723 * @param {Object} o An object which contains an Array of row objects in the property specified
20724 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20725 * which contains the total size of the dataset.
20726 * @return {Object} data A data block which is used by an Roo.data.Store object as
20727 * a cache of Roo.data.Records.
20729 readRecords : function(o){
20731 * After any data loads, the raw JSON data is available for further custom processing.
20735 var s = this.meta, Record = this.recordType,
20736 f = Record.prototype.fields, fi = f.items, fl = f.length;
20738 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20740 if(s.totalProperty) {
20741 this.getTotal = this.getJsonAccessor(s.totalProperty);
20743 if(s.successProperty) {
20744 this.getSuccess = this.getJsonAccessor(s.successProperty);
20746 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20748 var g = this.getJsonAccessor(s.id);
20749 this.getId = function(rec) {
20751 return (r === undefined || r === "") ? null : r;
20754 this.getId = function(){return null;};
20757 for(var jj = 0; jj < fl; jj++){
20759 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20760 this.ef[jj] = this.getJsonAccessor(map);
20764 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20765 if(s.totalProperty){
20766 var vt = parseInt(this.getTotal(o), 10);
20771 if(s.successProperty){
20772 var vs = this.getSuccess(o);
20773 if(vs === false || vs === 'false'){
20778 for(var i = 0; i < c; i++){
20781 var id = this.getId(n);
20782 for(var j = 0; j < fl; j++){
20784 var v = this.ef[j](n);
20786 Roo.log('missing convert for ' + f.name);
20790 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20792 var record = new Record(values, id);
20794 records[i] = record;
20799 totalRecords : totalRecords
20804 * Ext JS Library 1.1.1
20805 * Copyright(c) 2006-2007, Ext JS, LLC.
20807 * Originally Released Under LGPL - original licence link has changed is not relivant.
20810 * <script type="text/javascript">
20814 * @class Roo.data.XmlReader
20815 * @extends Roo.data.DataReader
20816 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20817 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20819 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20820 * header in the HTTP response must be set to "text/xml".</em>
20824 var RecordDef = Roo.data.Record.create([
20825 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20826 {name: 'occupation'} // This field will use "occupation" as the mapping.
20828 var myReader = new Roo.data.XmlReader({
20829 totalRecords: "results", // The element which contains the total dataset size (optional)
20830 record: "row", // The repeated element which contains row information
20831 id: "id" // The element within the row that provides an ID for the record (optional)
20835 * This would consume an XML file like this:
20839 <results>2</results>
20842 <name>Bill</name>
20843 <occupation>Gardener</occupation>
20847 <name>Ben</name>
20848 <occupation>Horticulturalist</occupation>
20852 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20853 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20854 * paged from the remote server.
20855 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20856 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20857 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20858 * a record identifier value.
20860 * Create a new XmlReader
20861 * @param {Object} meta Metadata configuration options
20862 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20863 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20864 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20866 Roo.data.XmlReader = function(meta, recordType){
20868 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20870 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20872 * This method is only used by a DataProxy which has retrieved data from a remote server.
20873 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20874 * to contain a method called 'responseXML' that returns an XML document object.
20875 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20876 * a cache of Roo.data.Records.
20878 read : function(response){
20879 var doc = response.responseXML;
20881 throw {message: "XmlReader.read: XML Document not available"};
20883 return this.readRecords(doc);
20887 * Create a data block containing Roo.data.Records from an XML document.
20888 * @param {Object} doc A parsed XML document.
20889 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20890 * a cache of Roo.data.Records.
20892 readRecords : function(doc){
20894 * After any data loads/reads, the raw XML Document is available for further custom processing.
20895 * @type XMLDocument
20897 this.xmlData = doc;
20898 var root = doc.documentElement || doc;
20899 var q = Roo.DomQuery;
20900 var recordType = this.recordType, fields = recordType.prototype.fields;
20901 var sid = this.meta.id;
20902 var totalRecords = 0, success = true;
20903 if(this.meta.totalRecords){
20904 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20907 if(this.meta.success){
20908 var sv = q.selectValue(this.meta.success, root, true);
20909 success = sv !== false && sv !== 'false';
20912 var ns = q.select(this.meta.record, root);
20913 for(var i = 0, len = ns.length; i < len; i++) {
20916 var id = sid ? q.selectValue(sid, n) : undefined;
20917 for(var j = 0, jlen = fields.length; j < jlen; j++){
20918 var f = fields.items[j];
20919 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20921 values[f.name] = v;
20923 var record = new recordType(values, id);
20925 records[records.length] = record;
20931 totalRecords : totalRecords || records.length
20936 * Ext JS Library 1.1.1
20937 * Copyright(c) 2006-2007, Ext JS, LLC.
20939 * Originally Released Under LGPL - original licence link has changed is not relivant.
20942 * <script type="text/javascript">
20946 * @class Roo.data.ArrayReader
20947 * @extends Roo.data.DataReader
20948 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20949 * Each element of that Array represents a row of data fields. The
20950 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20951 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20955 var RecordDef = Roo.data.Record.create([
20956 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20957 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20959 var myReader = new Roo.data.ArrayReader({
20960 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20964 * This would consume an Array like this:
20966 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20968 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20970 * Create a new JsonReader
20971 * @param {Object} meta Metadata configuration options.
20972 * @param {Object} recordType Either an Array of field definition objects
20973 * as specified to {@link Roo.data.Record#create},
20974 * or an {@link Roo.data.Record} object
20975 * created using {@link Roo.data.Record#create}.
20977 Roo.data.ArrayReader = function(meta, recordType){
20978 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20981 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20983 * Create a data block containing Roo.data.Records from an XML document.
20984 * @param {Object} o An Array of row objects which represents the dataset.
20985 * @return {Object} data A data block which is used by an Roo.data.Store object as
20986 * a cache of Roo.data.Records.
20988 readRecords : function(o){
20989 var sid = this.meta ? this.meta.id : null;
20990 var recordType = this.recordType, fields = recordType.prototype.fields;
20993 for(var i = 0; i < root.length; i++){
20996 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20997 for(var j = 0, jlen = fields.length; j < jlen; j++){
20998 var f = fields.items[j];
20999 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21000 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21002 values[f.name] = v;
21004 var record = new recordType(values, id);
21006 records[records.length] = record;
21010 totalRecords : records.length
21015 * Ext JS Library 1.1.1
21016 * Copyright(c) 2006-2007, Ext JS, LLC.
21018 * Originally Released Under LGPL - original licence link has changed is not relivant.
21021 * <script type="text/javascript">
21026 * @class Roo.data.Tree
21027 * @extends Roo.util.Observable
21028 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21029 * in the tree have most standard DOM functionality.
21031 * @param {Node} root (optional) The root node
21033 Roo.data.Tree = function(root){
21034 this.nodeHash = {};
21036 * The root node for this tree
21041 this.setRootNode(root);
21046 * Fires when a new child node is appended to a node in this tree.
21047 * @param {Tree} tree The owner tree
21048 * @param {Node} parent The parent node
21049 * @param {Node} node The newly appended node
21050 * @param {Number} index The index of the newly appended node
21055 * Fires when a child node is removed from a node in this tree.
21056 * @param {Tree} tree The owner tree
21057 * @param {Node} parent The parent node
21058 * @param {Node} node The child node removed
21063 * Fires when a node is moved to a new location in the tree
21064 * @param {Tree} tree The owner tree
21065 * @param {Node} node The node moved
21066 * @param {Node} oldParent The old parent of this node
21067 * @param {Node} newParent The new parent of this node
21068 * @param {Number} index The index it was moved to
21073 * Fires when a new child node is inserted in a node in this tree.
21074 * @param {Tree} tree The owner tree
21075 * @param {Node} parent The parent node
21076 * @param {Node} node The child node inserted
21077 * @param {Node} refNode The child node the node was inserted before
21081 * @event beforeappend
21082 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21083 * @param {Tree} tree The owner tree
21084 * @param {Node} parent The parent node
21085 * @param {Node} node The child node to be appended
21087 "beforeappend" : true,
21089 * @event beforeremove
21090 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21091 * @param {Tree} tree The owner tree
21092 * @param {Node} parent The parent node
21093 * @param {Node} node The child node to be removed
21095 "beforeremove" : true,
21097 * @event beforemove
21098 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21099 * @param {Tree} tree The owner tree
21100 * @param {Node} node The node being moved
21101 * @param {Node} oldParent The parent of the node
21102 * @param {Node} newParent The new parent the node is moving to
21103 * @param {Number} index The index it is being moved to
21105 "beforemove" : true,
21107 * @event beforeinsert
21108 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21109 * @param {Tree} tree The owner tree
21110 * @param {Node} parent The parent node
21111 * @param {Node} node The child node to be inserted
21112 * @param {Node} refNode The child node the node is being inserted before
21114 "beforeinsert" : true
21117 Roo.data.Tree.superclass.constructor.call(this);
21120 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21121 pathSeparator: "/",
21123 proxyNodeEvent : function(){
21124 return this.fireEvent.apply(this, arguments);
21128 * Returns the root node for this tree.
21131 getRootNode : function(){
21136 * Sets the root node for this tree.
21137 * @param {Node} node
21140 setRootNode : function(node){
21142 node.ownerTree = this;
21143 node.isRoot = true;
21144 this.registerNode(node);
21149 * Gets a node in this tree by its id.
21150 * @param {String} id
21153 getNodeById : function(id){
21154 return this.nodeHash[id];
21157 registerNode : function(node){
21158 this.nodeHash[node.id] = node;
21161 unregisterNode : function(node){
21162 delete this.nodeHash[node.id];
21165 toString : function(){
21166 return "[Tree"+(this.id?" "+this.id:"")+"]";
21171 * @class Roo.data.Node
21172 * @extends Roo.util.Observable
21173 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21174 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21176 * @param {Object} attributes The attributes/config for the node
21178 Roo.data.Node = function(attributes){
21180 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21183 this.attributes = attributes || {};
21184 this.leaf = this.attributes.leaf;
21186 * The node id. @type String
21188 this.id = this.attributes.id;
21190 this.id = Roo.id(null, "ynode-");
21191 this.attributes.id = this.id;
21196 * All child nodes of this node. @type Array
21198 this.childNodes = [];
21199 if(!this.childNodes.indexOf){ // indexOf is a must
21200 this.childNodes.indexOf = function(o){
21201 for(var i = 0, len = this.length; i < len; i++){
21210 * The parent node for this node. @type Node
21212 this.parentNode = null;
21214 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21216 this.firstChild = null;
21218 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21220 this.lastChild = null;
21222 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21224 this.previousSibling = null;
21226 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21228 this.nextSibling = null;
21233 * Fires when a new child node is appended
21234 * @param {Tree} tree The owner tree
21235 * @param {Node} this This node
21236 * @param {Node} node The newly appended node
21237 * @param {Number} index The index of the newly appended node
21242 * Fires when a child node is removed
21243 * @param {Tree} tree The owner tree
21244 * @param {Node} this This node
21245 * @param {Node} node The removed node
21250 * Fires when this node is moved to a new location in the tree
21251 * @param {Tree} tree The owner tree
21252 * @param {Node} this This node
21253 * @param {Node} oldParent The old parent of this node
21254 * @param {Node} newParent The new parent of this node
21255 * @param {Number} index The index it was moved to
21260 * Fires when a new child node is inserted.
21261 * @param {Tree} tree The owner tree
21262 * @param {Node} this This node
21263 * @param {Node} node The child node inserted
21264 * @param {Node} refNode The child node the node was inserted before
21268 * @event beforeappend
21269 * Fires before a new child is appended, return false to cancel the append.
21270 * @param {Tree} tree The owner tree
21271 * @param {Node} this This node
21272 * @param {Node} node The child node to be appended
21274 "beforeappend" : true,
21276 * @event beforeremove
21277 * Fires before a child is removed, return false to cancel the remove.
21278 * @param {Tree} tree The owner tree
21279 * @param {Node} this This node
21280 * @param {Node} node The child node to be removed
21282 "beforeremove" : true,
21284 * @event beforemove
21285 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21286 * @param {Tree} tree The owner tree
21287 * @param {Node} this This node
21288 * @param {Node} oldParent The parent of this node
21289 * @param {Node} newParent The new parent this node is moving to
21290 * @param {Number} index The index it is being moved to
21292 "beforemove" : true,
21294 * @event beforeinsert
21295 * Fires before a new child is inserted, return false to cancel the insert.
21296 * @param {Tree} tree The owner tree
21297 * @param {Node} this This node
21298 * @param {Node} node The child node to be inserted
21299 * @param {Node} refNode The child node the node is being inserted before
21301 "beforeinsert" : true
21303 this.listeners = this.attributes.listeners;
21304 Roo.data.Node.superclass.constructor.call(this);
21307 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21308 fireEvent : function(evtName){
21309 // first do standard event for this node
21310 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21313 // then bubble it up to the tree if the event wasn't cancelled
21314 var ot = this.getOwnerTree();
21316 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21324 * Returns true if this node is a leaf
21325 * @return {Boolean}
21327 isLeaf : function(){
21328 return this.leaf === true;
21332 setFirstChild : function(node){
21333 this.firstChild = node;
21337 setLastChild : function(node){
21338 this.lastChild = node;
21343 * Returns true if this node is the last child of its parent
21344 * @return {Boolean}
21346 isLast : function(){
21347 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21351 * Returns true if this node is the first child of its parent
21352 * @return {Boolean}
21354 isFirst : function(){
21355 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21358 hasChildNodes : function(){
21359 return !this.isLeaf() && this.childNodes.length > 0;
21363 * Insert node(s) as the last child node of this node.
21364 * @param {Node/Array} node The node or Array of nodes to append
21365 * @return {Node} The appended node if single append, or null if an array was passed
21367 appendChild : function(node){
21369 if(node instanceof Array){
21371 }else if(arguments.length > 1){
21374 // if passed an array or multiple args do them one by one
21376 for(var i = 0, len = multi.length; i < len; i++) {
21377 this.appendChild(multi[i]);
21380 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21383 var index = this.childNodes.length;
21384 var oldParent = node.parentNode;
21385 // it's a move, make sure we move it cleanly
21387 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21390 oldParent.removeChild(node);
21392 index = this.childNodes.length;
21394 this.setFirstChild(node);
21396 this.childNodes.push(node);
21397 node.parentNode = this;
21398 var ps = this.childNodes[index-1];
21400 node.previousSibling = ps;
21401 ps.nextSibling = node;
21403 node.previousSibling = null;
21405 node.nextSibling = null;
21406 this.setLastChild(node);
21407 node.setOwnerTree(this.getOwnerTree());
21408 this.fireEvent("append", this.ownerTree, this, node, index);
21410 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21417 * Removes a child node from this node.
21418 * @param {Node} node The node to remove
21419 * @return {Node} The removed node
21421 removeChild : function(node){
21422 var index = this.childNodes.indexOf(node);
21426 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21430 // remove it from childNodes collection
21431 this.childNodes.splice(index, 1);
21434 if(node.previousSibling){
21435 node.previousSibling.nextSibling = node.nextSibling;
21437 if(node.nextSibling){
21438 node.nextSibling.previousSibling = node.previousSibling;
21441 // update child refs
21442 if(this.firstChild == node){
21443 this.setFirstChild(node.nextSibling);
21445 if(this.lastChild == node){
21446 this.setLastChild(node.previousSibling);
21449 node.setOwnerTree(null);
21450 // clear any references from the node
21451 node.parentNode = null;
21452 node.previousSibling = null;
21453 node.nextSibling = null;
21454 this.fireEvent("remove", this.ownerTree, this, node);
21459 * Inserts the first node before the second node in this nodes childNodes collection.
21460 * @param {Node} node The node to insert
21461 * @param {Node} refNode The node to insert before (if null the node is appended)
21462 * @return {Node} The inserted node
21464 insertBefore : function(node, refNode){
21465 if(!refNode){ // like standard Dom, refNode can be null for append
21466 return this.appendChild(node);
21469 if(node == refNode){
21473 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21476 var index = this.childNodes.indexOf(refNode);
21477 var oldParent = node.parentNode;
21478 var refIndex = index;
21480 // when moving internally, indexes will change after remove
21481 if(oldParent == this && this.childNodes.indexOf(node) < index){
21485 // it's a move, make sure we move it cleanly
21487 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21490 oldParent.removeChild(node);
21493 this.setFirstChild(node);
21495 this.childNodes.splice(refIndex, 0, node);
21496 node.parentNode = this;
21497 var ps = this.childNodes[refIndex-1];
21499 node.previousSibling = ps;
21500 ps.nextSibling = node;
21502 node.previousSibling = null;
21504 node.nextSibling = refNode;
21505 refNode.previousSibling = node;
21506 node.setOwnerTree(this.getOwnerTree());
21507 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21509 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21515 * Returns the child node at the specified index.
21516 * @param {Number} index
21519 item : function(index){
21520 return this.childNodes[index];
21524 * Replaces one child node in this node with another.
21525 * @param {Node} newChild The replacement node
21526 * @param {Node} oldChild The node to replace
21527 * @return {Node} The replaced node
21529 replaceChild : function(newChild, oldChild){
21530 this.insertBefore(newChild, oldChild);
21531 this.removeChild(oldChild);
21536 * Returns the index of a child node
21537 * @param {Node} node
21538 * @return {Number} The index of the node or -1 if it was not found
21540 indexOf : function(child){
21541 return this.childNodes.indexOf(child);
21545 * Returns the tree this node is in.
21548 getOwnerTree : function(){
21549 // if it doesn't have one, look for one
21550 if(!this.ownerTree){
21554 this.ownerTree = p.ownerTree;
21560 return this.ownerTree;
21564 * Returns depth of this node (the root node has a depth of 0)
21567 getDepth : function(){
21570 while(p.parentNode){
21578 setOwnerTree : function(tree){
21579 // if it's move, we need to update everyone
21580 if(tree != this.ownerTree){
21581 if(this.ownerTree){
21582 this.ownerTree.unregisterNode(this);
21584 this.ownerTree = tree;
21585 var cs = this.childNodes;
21586 for(var i = 0, len = cs.length; i < len; i++) {
21587 cs[i].setOwnerTree(tree);
21590 tree.registerNode(this);
21596 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21597 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21598 * @return {String} The path
21600 getPath : function(attr){
21601 attr = attr || "id";
21602 var p = this.parentNode;
21603 var b = [this.attributes[attr]];
21605 b.unshift(p.attributes[attr]);
21608 var sep = this.getOwnerTree().pathSeparator;
21609 return sep + b.join(sep);
21613 * Bubbles up 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 bubble is stopped.
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 bubble : function(fn, scope, args){
21624 if(fn.call(scope || p, args || p) === false){
21632 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21633 * function call will be the scope provided or the current node. The arguments to the function
21634 * will be the args provided or the current node. If the function returns false at any point,
21635 * the cascade is stopped on that branch.
21636 * @param {Function} fn The function to call
21637 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21638 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21640 cascade : function(fn, scope, args){
21641 if(fn.call(scope || this, args || this) !== false){
21642 var cs = this.childNodes;
21643 for(var i = 0, len = cs.length; i < len; i++) {
21644 cs[i].cascade(fn, scope, args);
21650 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21651 * function call will be the scope provided or the current node. The arguments to the function
21652 * will be the args provided or the current node. If the function returns false at any point,
21653 * the iteration stops.
21654 * @param {Function} fn The function to call
21655 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21656 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21658 eachChild : function(fn, scope, args){
21659 var cs = this.childNodes;
21660 for(var i = 0, len = cs.length; i < len; i++) {
21661 if(fn.call(scope || this, args || cs[i]) === false){
21668 * Finds the first child that has the attribute with the specified value.
21669 * @param {String} attribute The attribute name
21670 * @param {Mixed} value The value to search for
21671 * @return {Node} The found child or null if none was found
21673 findChild : function(attribute, value){
21674 var cs = this.childNodes;
21675 for(var i = 0, len = cs.length; i < len; i++) {
21676 if(cs[i].attributes[attribute] == value){
21684 * Finds the first child by a custom function. The child matches if the function passed
21686 * @param {Function} fn
21687 * @param {Object} scope (optional)
21688 * @return {Node} The found child or null if none was found
21690 findChildBy : function(fn, scope){
21691 var cs = this.childNodes;
21692 for(var i = 0, len = cs.length; i < len; i++) {
21693 if(fn.call(scope||cs[i], cs[i]) === true){
21701 * Sorts this nodes children using the supplied sort function
21702 * @param {Function} fn
21703 * @param {Object} scope (optional)
21705 sort : function(fn, scope){
21706 var cs = this.childNodes;
21707 var len = cs.length;
21709 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21711 for(var i = 0; i < len; i++){
21713 n.previousSibling = cs[i-1];
21714 n.nextSibling = cs[i+1];
21716 this.setFirstChild(n);
21719 this.setLastChild(n);
21726 * Returns true if this node is an ancestor (at any point) of the passed node.
21727 * @param {Node} node
21728 * @return {Boolean}
21730 contains : function(node){
21731 return node.isAncestor(this);
21735 * Returns true if the passed node is an ancestor (at any point) of this node.
21736 * @param {Node} node
21737 * @return {Boolean}
21739 isAncestor : function(node){
21740 var p = this.parentNode;
21750 toString : function(){
21751 return "[Node"+(this.id?" "+this.id:"")+"]";
21755 * Ext JS Library 1.1.1
21756 * Copyright(c) 2006-2007, Ext JS, LLC.
21758 * Originally Released Under LGPL - original licence link has changed is not relivant.
21761 * <script type="text/javascript">
21766 * @class Roo.ComponentMgr
21767 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21770 Roo.ComponentMgr = function(){
21771 var all = new Roo.util.MixedCollection();
21775 * Registers a component.
21776 * @param {Roo.Component} c The component
21778 register : function(c){
21783 * Unregisters a component.
21784 * @param {Roo.Component} c The component
21786 unregister : function(c){
21791 * Returns a component by id
21792 * @param {String} id The component id
21794 get : function(id){
21795 return all.get(id);
21799 * Registers a function that will be called when a specified component is added to ComponentMgr
21800 * @param {String} id The component id
21801 * @param {Funtction} fn The callback function
21802 * @param {Object} scope The scope of the callback
21804 onAvailable : function(id, fn, scope){
21805 all.on("add", function(index, o){
21807 fn.call(scope || o, o);
21808 all.un("add", fn, scope);
21815 * Ext JS Library 1.1.1
21816 * Copyright(c) 2006-2007, Ext JS, LLC.
21818 * Originally Released Under LGPL - original licence link has changed is not relivant.
21821 * <script type="text/javascript">
21825 * @class Roo.Component
21826 * @extends Roo.util.Observable
21827 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21828 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21829 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21830 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21831 * All visual components (widgets) that require rendering into a layout should subclass Component.
21833 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21834 * 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
21835 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21837 Roo.Component = function(config){
21838 config = config || {};
21839 if(config.tagName || config.dom || typeof config == "string"){ // element object
21840 config = {el: config, id: config.id || config};
21842 this.initialConfig = config;
21844 Roo.apply(this, config);
21848 * Fires after the component is disabled.
21849 * @param {Roo.Component} this
21854 * Fires after the component is enabled.
21855 * @param {Roo.Component} this
21859 * @event beforeshow
21860 * Fires before the component is shown. Return false to stop the show.
21861 * @param {Roo.Component} this
21866 * Fires after the component is shown.
21867 * @param {Roo.Component} this
21871 * @event beforehide
21872 * Fires before the component is hidden. Return false to stop the hide.
21873 * @param {Roo.Component} this
21878 * Fires after the component is hidden.
21879 * @param {Roo.Component} this
21883 * @event beforerender
21884 * Fires before the component is rendered. Return false to stop the render.
21885 * @param {Roo.Component} this
21887 beforerender : true,
21890 * Fires after the component is rendered.
21891 * @param {Roo.Component} this
21895 * @event beforedestroy
21896 * Fires before the component is destroyed. Return false to stop the destroy.
21897 * @param {Roo.Component} this
21899 beforedestroy : true,
21902 * Fires after the component is destroyed.
21903 * @param {Roo.Component} this
21908 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21910 Roo.ComponentMgr.register(this);
21911 Roo.Component.superclass.constructor.call(this);
21912 this.initComponent();
21913 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21914 this.render(this.renderTo);
21915 delete this.renderTo;
21920 Roo.Component.AUTO_ID = 1000;
21922 Roo.extend(Roo.Component, Roo.util.Observable, {
21924 * @scope Roo.Component.prototype
21926 * true if this component is hidden. Read-only.
21931 * true if this component is disabled. Read-only.
21936 * true if this component has been rendered. Read-only.
21940 /** @cfg {String} disableClass
21941 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21943 disabledClass : "x-item-disabled",
21944 /** @cfg {Boolean} allowDomMove
21945 * Whether the component can move the Dom node when rendering (defaults to true).
21947 allowDomMove : true,
21948 /** @cfg {String} hideMode
21949 * How this component should hidden. Supported values are
21950 * "visibility" (css visibility), "offsets" (negative offset position) and
21951 * "display" (css display) - defaults to "display".
21953 hideMode: 'display',
21956 ctype : "Roo.Component",
21959 * @cfg {String} actionMode
21960 * which property holds the element that used for hide() / show() / disable() / enable()
21966 getActionEl : function(){
21967 return this[this.actionMode];
21970 initComponent : Roo.emptyFn,
21972 * If this is a lazy rendering component, render it to its container element.
21973 * @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.
21975 render : function(container, position){
21976 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21977 if(!container && this.el){
21978 this.el = Roo.get(this.el);
21979 container = this.el.dom.parentNode;
21980 this.allowDomMove = false;
21982 this.container = Roo.get(container);
21983 this.rendered = true;
21984 if(position !== undefined){
21985 if(typeof position == 'number'){
21986 position = this.container.dom.childNodes[position];
21988 position = Roo.getDom(position);
21991 this.onRender(this.container, position || null);
21993 this.el.addClass(this.cls);
21997 this.el.applyStyles(this.style);
22000 this.fireEvent("render", this);
22001 this.afterRender(this.container);
22013 // default function is not really useful
22014 onRender : function(ct, position){
22016 this.el = Roo.get(this.el);
22017 if(this.allowDomMove !== false){
22018 ct.dom.insertBefore(this.el.dom, position);
22024 getAutoCreate : function(){
22025 var cfg = typeof this.autoCreate == "object" ?
22026 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22027 if(this.id && !cfg.id){
22034 afterRender : Roo.emptyFn,
22037 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22038 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22040 destroy : function(){
22041 if(this.fireEvent("beforedestroy", this) !== false){
22042 this.purgeListeners();
22043 this.beforeDestroy();
22045 this.el.removeAllListeners();
22047 if(this.actionMode == "container"){
22048 this.container.remove();
22052 Roo.ComponentMgr.unregister(this);
22053 this.fireEvent("destroy", this);
22058 beforeDestroy : function(){
22063 onDestroy : function(){
22068 * Returns the underlying {@link Roo.Element}.
22069 * @return {Roo.Element} The element
22071 getEl : function(){
22076 * Returns the id of this component.
22079 getId : function(){
22084 * Try to focus this component.
22085 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22086 * @return {Roo.Component} this
22088 focus : function(selectText){
22091 if(selectText === true){
22092 this.el.dom.select();
22107 * Disable this component.
22108 * @return {Roo.Component} this
22110 disable : function(){
22114 this.disabled = true;
22115 this.fireEvent("disable", this);
22120 onDisable : function(){
22121 this.getActionEl().addClass(this.disabledClass);
22122 this.el.dom.disabled = true;
22126 * Enable this component.
22127 * @return {Roo.Component} this
22129 enable : function(){
22133 this.disabled = false;
22134 this.fireEvent("enable", this);
22139 onEnable : function(){
22140 this.getActionEl().removeClass(this.disabledClass);
22141 this.el.dom.disabled = false;
22145 * Convenience function for setting disabled/enabled by boolean.
22146 * @param {Boolean} disabled
22148 setDisabled : function(disabled){
22149 this[disabled ? "disable" : "enable"]();
22153 * Show this component.
22154 * @return {Roo.Component} this
22157 if(this.fireEvent("beforeshow", this) !== false){
22158 this.hidden = false;
22162 this.fireEvent("show", this);
22168 onShow : function(){
22169 var ae = this.getActionEl();
22170 if(this.hideMode == 'visibility'){
22171 ae.dom.style.visibility = "visible";
22172 }else if(this.hideMode == 'offsets'){
22173 ae.removeClass('x-hidden');
22175 ae.dom.style.display = "";
22180 * Hide this component.
22181 * @return {Roo.Component} this
22184 if(this.fireEvent("beforehide", this) !== false){
22185 this.hidden = true;
22189 this.fireEvent("hide", this);
22195 onHide : function(){
22196 var ae = this.getActionEl();
22197 if(this.hideMode == 'visibility'){
22198 ae.dom.style.visibility = "hidden";
22199 }else if(this.hideMode == 'offsets'){
22200 ae.addClass('x-hidden');
22202 ae.dom.style.display = "none";
22207 * Convenience function to hide or show this component by boolean.
22208 * @param {Boolean} visible True to show, false to hide
22209 * @return {Roo.Component} this
22211 setVisible: function(visible){
22221 * Returns true if this component is visible.
22223 isVisible : function(){
22224 return this.getActionEl().isVisible();
22227 cloneConfig : function(overrides){
22228 overrides = overrides || {};
22229 var id = overrides.id || Roo.id();
22230 var cfg = Roo.applyIf(overrides, this.initialConfig);
22231 cfg.id = id; // prevent dup id
22232 return new this.constructor(cfg);
22236 * Ext JS Library 1.1.1
22237 * Copyright(c) 2006-2007, Ext JS, LLC.
22239 * Originally Released Under LGPL - original licence link has changed is not relivant.
22242 * <script type="text/javascript">
22247 * @extends Roo.Element
22248 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22249 * automatic maintaining of shadow/shim positions.
22250 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22251 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22252 * you can pass a string with a CSS class name. False turns off the shadow.
22253 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22254 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22255 * @cfg {String} cls CSS class to add to the element
22256 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22257 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22259 * @param {Object} config An object with config options.
22260 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22263 Roo.Layer = function(config, existingEl){
22264 config = config || {};
22265 var dh = Roo.DomHelper;
22266 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22268 this.dom = Roo.getDom(existingEl);
22271 var o = config.dh || {tag: "div", cls: "x-layer"};
22272 this.dom = dh.append(pel, o);
22275 this.addClass(config.cls);
22277 this.constrain = config.constrain !== false;
22278 this.visibilityMode = Roo.Element.VISIBILITY;
22280 this.id = this.dom.id = config.id;
22282 this.id = Roo.id(this.dom);
22284 this.zindex = config.zindex || this.getZIndex();
22285 this.position("absolute", this.zindex);
22287 this.shadowOffset = config.shadowOffset || 4;
22288 this.shadow = new Roo.Shadow({
22289 offset : this.shadowOffset,
22290 mode : config.shadow
22293 this.shadowOffset = 0;
22295 this.useShim = config.shim !== false && Roo.useShims;
22296 this.useDisplay = config.useDisplay;
22300 var supr = Roo.Element.prototype;
22302 // shims are shared among layer to keep from having 100 iframes
22305 Roo.extend(Roo.Layer, Roo.Element, {
22307 getZIndex : function(){
22308 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22311 getShim : function(){
22318 var shim = shims.shift();
22320 shim = this.createShim();
22321 shim.enableDisplayMode('block');
22322 shim.dom.style.display = 'none';
22323 shim.dom.style.visibility = 'visible';
22325 var pn = this.dom.parentNode;
22326 if(shim.dom.parentNode != pn){
22327 pn.insertBefore(shim.dom, this.dom);
22329 shim.setStyle('z-index', this.getZIndex()-2);
22334 hideShim : function(){
22336 this.shim.setDisplayed(false);
22337 shims.push(this.shim);
22342 disableShadow : function(){
22344 this.shadowDisabled = true;
22345 this.shadow.hide();
22346 this.lastShadowOffset = this.shadowOffset;
22347 this.shadowOffset = 0;
22351 enableShadow : function(show){
22353 this.shadowDisabled = false;
22354 this.shadowOffset = this.lastShadowOffset;
22355 delete this.lastShadowOffset;
22363 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22364 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22365 sync : function(doShow){
22366 var sw = this.shadow;
22367 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22368 var sh = this.getShim();
22370 var w = this.getWidth(),
22371 h = this.getHeight();
22373 var l = this.getLeft(true),
22374 t = this.getTop(true);
22376 if(sw && !this.shadowDisabled){
22377 if(doShow && !sw.isVisible()){
22380 sw.realign(l, t, w, h);
22386 // fit the shim behind the shadow, so it is shimmed too
22387 var a = sw.adjusts, s = sh.dom.style;
22388 s.left = (Math.min(l, l+a.l))+"px";
22389 s.top = (Math.min(t, t+a.t))+"px";
22390 s.width = (w+a.w)+"px";
22391 s.height = (h+a.h)+"px";
22398 sh.setLeftTop(l, t);
22405 destroy : function(){
22408 this.shadow.hide();
22410 this.removeAllListeners();
22411 var pn = this.dom.parentNode;
22413 pn.removeChild(this.dom);
22415 Roo.Element.uncache(this.id);
22418 remove : function(){
22423 beginUpdate : function(){
22424 this.updating = true;
22428 endUpdate : function(){
22429 this.updating = false;
22434 hideUnders : function(negOffset){
22436 this.shadow.hide();
22442 constrainXY : function(){
22443 if(this.constrain){
22444 var vw = Roo.lib.Dom.getViewWidth(),
22445 vh = Roo.lib.Dom.getViewHeight();
22446 var s = Roo.get(document).getScroll();
22448 var xy = this.getXY();
22449 var x = xy[0], y = xy[1];
22450 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22451 // only move it if it needs it
22453 // first validate right/bottom
22454 if((x + w) > vw+s.left){
22455 x = vw - w - this.shadowOffset;
22458 if((y + h) > vh+s.top){
22459 y = vh - h - this.shadowOffset;
22462 // then make sure top/left isn't negative
22473 var ay = this.avoidY;
22474 if(y <= ay && (y+h) >= ay){
22480 supr.setXY.call(this, xy);
22486 isVisible : function(){
22487 return this.visible;
22491 showAction : function(){
22492 this.visible = true; // track visibility to prevent getStyle calls
22493 if(this.useDisplay === true){
22494 this.setDisplayed("");
22495 }else if(this.lastXY){
22496 supr.setXY.call(this, this.lastXY);
22497 }else if(this.lastLT){
22498 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22503 hideAction : function(){
22504 this.visible = false;
22505 if(this.useDisplay === true){
22506 this.setDisplayed(false);
22508 this.setLeftTop(-10000,-10000);
22512 // overridden Element method
22513 setVisible : function(v, a, d, c, e){
22518 var cb = function(){
22523 }.createDelegate(this);
22524 supr.setVisible.call(this, true, true, d, cb, e);
22527 this.hideUnders(true);
22536 }.createDelegate(this);
22538 supr.setVisible.call(this, v, a, d, cb, e);
22547 storeXY : function(xy){
22548 delete this.lastLT;
22552 storeLeftTop : function(left, top){
22553 delete this.lastXY;
22554 this.lastLT = [left, top];
22558 beforeFx : function(){
22559 this.beforeAction();
22560 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22564 afterFx : function(){
22565 Roo.Layer.superclass.afterFx.apply(this, arguments);
22566 this.sync(this.isVisible());
22570 beforeAction : function(){
22571 if(!this.updating && this.shadow){
22572 this.shadow.hide();
22576 // overridden Element method
22577 setLeft : function(left){
22578 this.storeLeftTop(left, this.getTop(true));
22579 supr.setLeft.apply(this, arguments);
22583 setTop : function(top){
22584 this.storeLeftTop(this.getLeft(true), top);
22585 supr.setTop.apply(this, arguments);
22589 setLeftTop : function(left, top){
22590 this.storeLeftTop(left, top);
22591 supr.setLeftTop.apply(this, arguments);
22595 setXY : function(xy, a, d, c, e){
22597 this.beforeAction();
22599 var cb = this.createCB(c);
22600 supr.setXY.call(this, xy, a, d, cb, e);
22607 createCB : function(c){
22618 // overridden Element method
22619 setX : function(x, a, d, c, e){
22620 this.setXY([x, this.getY()], a, d, c, e);
22623 // overridden Element method
22624 setY : function(y, a, d, c, e){
22625 this.setXY([this.getX(), y], a, d, c, e);
22628 // overridden Element method
22629 setSize : function(w, h, a, d, c, e){
22630 this.beforeAction();
22631 var cb = this.createCB(c);
22632 supr.setSize.call(this, w, h, a, d, cb, e);
22638 // overridden Element method
22639 setWidth : function(w, a, d, c, e){
22640 this.beforeAction();
22641 var cb = this.createCB(c);
22642 supr.setWidth.call(this, w, a, d, cb, e);
22648 // overridden Element method
22649 setHeight : function(h, a, d, c, e){
22650 this.beforeAction();
22651 var cb = this.createCB(c);
22652 supr.setHeight.call(this, h, a, d, cb, e);
22658 // overridden Element method
22659 setBounds : function(x, y, w, h, a, d, c, e){
22660 this.beforeAction();
22661 var cb = this.createCB(c);
22663 this.storeXY([x, y]);
22664 supr.setXY.call(this, [x, y]);
22665 supr.setSize.call(this, w, h, a, d, cb, e);
22668 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22674 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22675 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22676 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22677 * @param {Number} zindex The new z-index to set
22678 * @return {this} The Layer
22680 setZIndex : function(zindex){
22681 this.zindex = zindex;
22682 this.setStyle("z-index", zindex + 2);
22684 this.shadow.setZIndex(zindex + 1);
22687 this.shim.setStyle("z-index", zindex);
22693 * Ext JS Library 1.1.1
22694 * Copyright(c) 2006-2007, Ext JS, LLC.
22696 * Originally Released Under LGPL - original licence link has changed is not relivant.
22699 * <script type="text/javascript">
22704 * @class Roo.Shadow
22705 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22706 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22707 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22709 * Create a new Shadow
22710 * @param {Object} config The config object
22712 Roo.Shadow = function(config){
22713 Roo.apply(this, config);
22714 if(typeof this.mode != "string"){
22715 this.mode = this.defaultMode;
22717 var o = this.offset, a = {h: 0};
22718 var rad = Math.floor(this.offset/2);
22719 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22725 a.l -= this.offset + rad;
22726 a.t -= this.offset + rad;
22737 a.l -= (this.offset - rad);
22738 a.t -= this.offset + rad;
22740 a.w -= (this.offset - rad)*2;
22751 a.l -= (this.offset - rad);
22752 a.t -= (this.offset - rad);
22754 a.w -= (this.offset + rad + 1);
22755 a.h -= (this.offset + rad);
22764 Roo.Shadow.prototype = {
22766 * @cfg {String} mode
22767 * The shadow display mode. Supports the following options:<br />
22768 * sides: Shadow displays on both sides and bottom only<br />
22769 * frame: Shadow displays equally on all four sides<br />
22770 * drop: Traditional bottom-right drop shadow (default)
22773 * @cfg {String} offset
22774 * The number of pixels to offset the shadow from the element (defaults to 4)
22779 defaultMode: "drop",
22782 * Displays the shadow under the target element
22783 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22785 show : function(target){
22786 target = Roo.get(target);
22788 this.el = Roo.Shadow.Pool.pull();
22789 if(this.el.dom.nextSibling != target.dom){
22790 this.el.insertBefore(target);
22793 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22795 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22798 target.getLeft(true),
22799 target.getTop(true),
22803 this.el.dom.style.display = "block";
22807 * Returns true if the shadow is visible, else false
22809 isVisible : function(){
22810 return this.el ? true : false;
22814 * Direct alignment when values are already available. Show must be called at least once before
22815 * calling this method to ensure it is initialized.
22816 * @param {Number} left The target element left position
22817 * @param {Number} top The target element top position
22818 * @param {Number} width The target element width
22819 * @param {Number} height The target element height
22821 realign : function(l, t, w, h){
22825 var a = this.adjusts, d = this.el.dom, s = d.style;
22827 s.left = (l+a.l)+"px";
22828 s.top = (t+a.t)+"px";
22829 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22831 if(s.width != sws || s.height != shs){
22835 var cn = d.childNodes;
22836 var sww = Math.max(0, (sw-12))+"px";
22837 cn[0].childNodes[1].style.width = sww;
22838 cn[1].childNodes[1].style.width = sww;
22839 cn[2].childNodes[1].style.width = sww;
22840 cn[1].style.height = Math.max(0, (sh-12))+"px";
22846 * Hides this shadow
22850 this.el.dom.style.display = "none";
22851 Roo.Shadow.Pool.push(this.el);
22857 * Adjust the z-index of this shadow
22858 * @param {Number} zindex The new z-index
22860 setZIndex : function(z){
22863 this.el.setStyle("z-index", z);
22868 // Private utility class that manages the internal Shadow cache
22869 Roo.Shadow.Pool = function(){
22871 var markup = Roo.isIE ?
22872 '<div class="x-ie-shadow"></div>' :
22873 '<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>';
22876 var sh = p.shift();
22878 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22879 sh.autoBoxAdjust = false;
22884 push : function(sh){
22890 * Ext JS Library 1.1.1
22891 * Copyright(c) 2006-2007, Ext JS, LLC.
22893 * Originally Released Under LGPL - original licence link has changed is not relivant.
22896 * <script type="text/javascript">
22900 * @class Roo.BoxComponent
22901 * @extends Roo.Component
22902 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22903 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22904 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22905 * layout containers.
22907 * @param {Roo.Element/String/Object} config The configuration options.
22909 Roo.BoxComponent = function(config){
22910 Roo.Component.call(this, config);
22914 * Fires after the component is resized.
22915 * @param {Roo.Component} this
22916 * @param {Number} adjWidth The box-adjusted width that was set
22917 * @param {Number} adjHeight The box-adjusted height that was set
22918 * @param {Number} rawWidth The width that was originally specified
22919 * @param {Number} rawHeight The height that was originally specified
22924 * Fires after the component is moved.
22925 * @param {Roo.Component} this
22926 * @param {Number} x The new x position
22927 * @param {Number} y The new y position
22933 Roo.extend(Roo.BoxComponent, Roo.Component, {
22934 // private, set in afterRender to signify that the component has been rendered
22936 // private, used to defer height settings to subclasses
22937 deferHeight: false,
22938 /** @cfg {Number} width
22939 * width (optional) size of component
22941 /** @cfg {Number} height
22942 * height (optional) size of component
22946 * Sets the width and height of the component. This method fires the resize event. This method can accept
22947 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22948 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22949 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22950 * @return {Roo.BoxComponent} this
22952 setSize : function(w, h){
22953 // support for standard size objects
22954 if(typeof w == 'object'){
22959 if(!this.boxReady){
22965 // prevent recalcs when not needed
22966 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22969 this.lastSize = {width: w, height: h};
22971 var adj = this.adjustSize(w, h);
22972 var aw = adj.width, ah = adj.height;
22973 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22974 var rz = this.getResizeEl();
22975 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22976 rz.setSize(aw, ah);
22977 }else if(!this.deferHeight && ah !== undefined){
22979 }else if(aw !== undefined){
22982 this.onResize(aw, ah, w, h);
22983 this.fireEvent('resize', this, aw, ah, w, h);
22989 * Gets the current size of the component's underlying element.
22990 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22992 getSize : function(){
22993 return this.el.getSize();
22997 * Gets the current XY position of the component's underlying element.
22998 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22999 * @return {Array} The XY position of the element (e.g., [100, 200])
23001 getPosition : function(local){
23002 if(local === true){
23003 return [this.el.getLeft(true), this.el.getTop(true)];
23005 return this.xy || this.el.getXY();
23009 * Gets the current box measurements of the component's underlying element.
23010 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23011 * @returns {Object} box An object in the format {x, y, width, height}
23013 getBox : function(local){
23014 var s = this.el.getSize();
23016 s.x = this.el.getLeft(true);
23017 s.y = this.el.getTop(true);
23019 var xy = this.xy || this.el.getXY();
23027 * Sets the current box measurements of the component's underlying element.
23028 * @param {Object} box An object in the format {x, y, width, height}
23029 * @returns {Roo.BoxComponent} this
23031 updateBox : function(box){
23032 this.setSize(box.width, box.height);
23033 this.setPagePosition(box.x, box.y);
23038 getResizeEl : function(){
23039 return this.resizeEl || this.el;
23043 getPositionEl : function(){
23044 return this.positionEl || this.el;
23048 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23049 * This method fires the move event.
23050 * @param {Number} left The new left
23051 * @param {Number} top The new top
23052 * @returns {Roo.BoxComponent} this
23054 setPosition : function(x, y){
23057 if(!this.boxReady){
23060 var adj = this.adjustPosition(x, y);
23061 var ax = adj.x, ay = adj.y;
23063 var el = this.getPositionEl();
23064 if(ax !== undefined || ay !== undefined){
23065 if(ax !== undefined && ay !== undefined){
23066 el.setLeftTop(ax, ay);
23067 }else if(ax !== undefined){
23069 }else if(ay !== undefined){
23072 this.onPosition(ax, ay);
23073 this.fireEvent('move', this, ax, ay);
23079 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23080 * This method fires the move event.
23081 * @param {Number} x The new x position
23082 * @param {Number} y The new y position
23083 * @returns {Roo.BoxComponent} this
23085 setPagePosition : function(x, y){
23088 if(!this.boxReady){
23091 if(x === undefined || y === undefined){ // cannot translate undefined points
23094 var p = this.el.translatePoints(x, y);
23095 this.setPosition(p.left, p.top);
23100 onRender : function(ct, position){
23101 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23103 this.resizeEl = Roo.get(this.resizeEl);
23105 if(this.positionEl){
23106 this.positionEl = Roo.get(this.positionEl);
23111 afterRender : function(){
23112 Roo.BoxComponent.superclass.afterRender.call(this);
23113 this.boxReady = true;
23114 this.setSize(this.width, this.height);
23115 if(this.x || this.y){
23116 this.setPosition(this.x, this.y);
23118 if(this.pageX || this.pageY){
23119 this.setPagePosition(this.pageX, this.pageY);
23124 * Force the component's size to recalculate based on the underlying element's current height and width.
23125 * @returns {Roo.BoxComponent} this
23127 syncSize : function(){
23128 delete this.lastSize;
23129 this.setSize(this.el.getWidth(), this.el.getHeight());
23134 * Called after the component is resized, this method is empty by default but can be implemented by any
23135 * subclass that needs to perform custom logic after a resize occurs.
23136 * @param {Number} adjWidth The box-adjusted width that was set
23137 * @param {Number} adjHeight The box-adjusted height that was set
23138 * @param {Number} rawWidth The width that was originally specified
23139 * @param {Number} rawHeight The height that was originally specified
23141 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23146 * Called after the component is moved, this method is empty by default but can be implemented by any
23147 * subclass that needs to perform custom logic after a move occurs.
23148 * @param {Number} x The new x position
23149 * @param {Number} y The new y position
23151 onPosition : function(x, y){
23156 adjustSize : function(w, h){
23157 if(this.autoWidth){
23160 if(this.autoHeight){
23163 return {width : w, height: h};
23167 adjustPosition : function(x, y){
23168 return {x : x, y: y};
23172 * Ext JS Library 1.1.1
23173 * Copyright(c) 2006-2007, Ext JS, LLC.
23175 * Originally Released Under LGPL - original licence link has changed is not relivant.
23178 * <script type="text/javascript">
23183 * @class Roo.SplitBar
23184 * @extends Roo.util.Observable
23185 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23189 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23190 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23191 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23192 split.minSize = 100;
23193 split.maxSize = 600;
23194 split.animate = true;
23195 split.on('moved', splitterMoved);
23198 * Create a new SplitBar
23199 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23200 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23201 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23202 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23203 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23204 position of the SplitBar).
23206 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23209 this.el = Roo.get(dragElement, true);
23210 this.el.dom.unselectable = "on";
23212 this.resizingEl = Roo.get(resizingElement, true);
23216 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23217 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23220 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23223 * The minimum size of the resizing element. (Defaults to 0)
23229 * The maximum size of the resizing element. (Defaults to 2000)
23232 this.maxSize = 2000;
23235 * Whether to animate the transition to the new size
23238 this.animate = false;
23241 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23244 this.useShim = false;
23249 if(!existingProxy){
23251 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23253 this.proxy = Roo.get(existingProxy).dom;
23256 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23259 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23262 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23265 this.dragSpecs = {};
23268 * @private The adapter to use to positon and resize elements
23270 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23271 this.adapter.init(this);
23273 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23275 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23276 this.el.addClass("x-splitbar-h");
23279 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23280 this.el.addClass("x-splitbar-v");
23286 * Fires when the splitter is moved (alias for {@link #event-moved})
23287 * @param {Roo.SplitBar} this
23288 * @param {Number} newSize the new width or height
23293 * Fires when the splitter is moved
23294 * @param {Roo.SplitBar} this
23295 * @param {Number} newSize the new width or height
23299 * @event beforeresize
23300 * Fires before the splitter is dragged
23301 * @param {Roo.SplitBar} this
23303 "beforeresize" : true,
23305 "beforeapply" : true
23308 Roo.util.Observable.call(this);
23311 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23312 onStartProxyDrag : function(x, y){
23313 this.fireEvent("beforeresize", this);
23315 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23317 o.enableDisplayMode("block");
23318 // all splitbars share the same overlay
23319 Roo.SplitBar.prototype.overlay = o;
23321 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23322 this.overlay.show();
23323 Roo.get(this.proxy).setDisplayed("block");
23324 var size = this.adapter.getElementSize(this);
23325 this.activeMinSize = this.getMinimumSize();;
23326 this.activeMaxSize = this.getMaximumSize();;
23327 var c1 = size - this.activeMinSize;
23328 var c2 = Math.max(this.activeMaxSize - size, 0);
23329 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23330 this.dd.resetConstraints();
23331 this.dd.setXConstraint(
23332 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23333 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23335 this.dd.setYConstraint(0, 0);
23337 this.dd.resetConstraints();
23338 this.dd.setXConstraint(0, 0);
23339 this.dd.setYConstraint(
23340 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23341 this.placement == Roo.SplitBar.TOP ? c2 : c1
23344 this.dragSpecs.startSize = size;
23345 this.dragSpecs.startPoint = [x, y];
23346 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23350 * @private Called after the drag operation by the DDProxy
23352 onEndProxyDrag : function(e){
23353 Roo.get(this.proxy).setDisplayed(false);
23354 var endPoint = Roo.lib.Event.getXY(e);
23356 this.overlay.hide();
23359 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23360 newSize = this.dragSpecs.startSize +
23361 (this.placement == Roo.SplitBar.LEFT ?
23362 endPoint[0] - this.dragSpecs.startPoint[0] :
23363 this.dragSpecs.startPoint[0] - endPoint[0]
23366 newSize = this.dragSpecs.startSize +
23367 (this.placement == Roo.SplitBar.TOP ?
23368 endPoint[1] - this.dragSpecs.startPoint[1] :
23369 this.dragSpecs.startPoint[1] - endPoint[1]
23372 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23373 if(newSize != this.dragSpecs.startSize){
23374 if(this.fireEvent('beforeapply', this, newSize) !== false){
23375 this.adapter.setElementSize(this, newSize);
23376 this.fireEvent("moved", this, newSize);
23377 this.fireEvent("resize", this, newSize);
23383 * Get the adapter this SplitBar uses
23384 * @return The adapter object
23386 getAdapter : function(){
23387 return this.adapter;
23391 * Set the adapter this SplitBar uses
23392 * @param {Object} adapter A SplitBar adapter object
23394 setAdapter : function(adapter){
23395 this.adapter = adapter;
23396 this.adapter.init(this);
23400 * Gets the minimum size for the resizing element
23401 * @return {Number} The minimum size
23403 getMinimumSize : function(){
23404 return this.minSize;
23408 * Sets the minimum size for the resizing element
23409 * @param {Number} minSize The minimum size
23411 setMinimumSize : function(minSize){
23412 this.minSize = minSize;
23416 * Gets the maximum size for the resizing element
23417 * @return {Number} The maximum size
23419 getMaximumSize : function(){
23420 return this.maxSize;
23424 * Sets the maximum size for the resizing element
23425 * @param {Number} maxSize The maximum size
23427 setMaximumSize : function(maxSize){
23428 this.maxSize = maxSize;
23432 * Sets the initialize size for the resizing element
23433 * @param {Number} size The initial size
23435 setCurrentSize : function(size){
23436 var oldAnimate = this.animate;
23437 this.animate = false;
23438 this.adapter.setElementSize(this, size);
23439 this.animate = oldAnimate;
23443 * Destroy this splitbar.
23444 * @param {Boolean} removeEl True to remove the element
23446 destroy : function(removeEl){
23448 this.shim.remove();
23451 this.proxy.parentNode.removeChild(this.proxy);
23459 * @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.
23461 Roo.SplitBar.createProxy = function(dir){
23462 var proxy = new Roo.Element(document.createElement("div"));
23463 proxy.unselectable();
23464 var cls = 'x-splitbar-proxy';
23465 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23466 document.body.appendChild(proxy.dom);
23471 * @class Roo.SplitBar.BasicLayoutAdapter
23472 * Default Adapter. It assumes the splitter and resizing element are not positioned
23473 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23475 Roo.SplitBar.BasicLayoutAdapter = function(){
23478 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23479 // do nothing for now
23480 init : function(s){
23484 * Called before drag operations to get the current size of the resizing element.
23485 * @param {Roo.SplitBar} s The SplitBar using this adapter
23487 getElementSize : function(s){
23488 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23489 return s.resizingEl.getWidth();
23491 return s.resizingEl.getHeight();
23496 * Called after drag operations to set the size of the resizing element.
23497 * @param {Roo.SplitBar} s The SplitBar using this adapter
23498 * @param {Number} newSize The new size to set
23499 * @param {Function} onComplete A function to be invoked when resizing is complete
23501 setElementSize : function(s, newSize, onComplete){
23502 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23504 s.resizingEl.setWidth(newSize);
23506 onComplete(s, newSize);
23509 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23514 s.resizingEl.setHeight(newSize);
23516 onComplete(s, newSize);
23519 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23526 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23527 * @extends Roo.SplitBar.BasicLayoutAdapter
23528 * Adapter that moves the splitter element to align with the resized sizing element.
23529 * Used with an absolute positioned SplitBar.
23530 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23531 * document.body, make sure you assign an id to the body element.
23533 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23534 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23535 this.container = Roo.get(container);
23538 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23539 init : function(s){
23540 this.basic.init(s);
23543 getElementSize : function(s){
23544 return this.basic.getElementSize(s);
23547 setElementSize : function(s, newSize, onComplete){
23548 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23551 moveSplitter : function(s){
23552 var yes = Roo.SplitBar;
23553 switch(s.placement){
23555 s.el.setX(s.resizingEl.getRight());
23558 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23561 s.el.setY(s.resizingEl.getBottom());
23564 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23571 * Orientation constant - Create a vertical SplitBar
23575 Roo.SplitBar.VERTICAL = 1;
23578 * Orientation constant - Create a horizontal SplitBar
23582 Roo.SplitBar.HORIZONTAL = 2;
23585 * Placement constant - The resizing element is to the left of the splitter element
23589 Roo.SplitBar.LEFT = 1;
23592 * Placement constant - The resizing element is to the right of the splitter element
23596 Roo.SplitBar.RIGHT = 2;
23599 * Placement constant - The resizing element is positioned above the splitter element
23603 Roo.SplitBar.TOP = 3;
23606 * Placement constant - The resizing element is positioned under splitter element
23610 Roo.SplitBar.BOTTOM = 4;
23613 * Ext JS Library 1.1.1
23614 * Copyright(c) 2006-2007, Ext JS, LLC.
23616 * Originally Released Under LGPL - original licence link has changed is not relivant.
23619 * <script type="text/javascript">
23624 * @extends Roo.util.Observable
23625 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23626 * This class also supports single and multi selection modes. <br>
23627 * Create a data model bound view:
23629 var store = new Roo.data.Store(...);
23631 var view = new Roo.View({
23633 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23635 singleSelect: true,
23636 selectedClass: "ydataview-selected",
23640 // listen for node click?
23641 view.on("click", function(vw, index, node, e){
23642 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23646 dataModel.load("foobar.xml");
23648 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23650 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23651 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23653 * Note: old style constructor is still suported (container, template, config)
23656 * Create a new View
23657 * @param {Object} config The config object
23660 Roo.View = function(config, depreciated_tpl, depreciated_config){
23662 if (typeof(depreciated_tpl) == 'undefined') {
23663 // new way.. - universal constructor.
23664 Roo.apply(this, config);
23665 this.el = Roo.get(this.el);
23668 this.el = Roo.get(config);
23669 this.tpl = depreciated_tpl;
23670 Roo.apply(this, depreciated_config);
23674 if(typeof(this.tpl) == "string"){
23675 this.tpl = new Roo.Template(this.tpl);
23677 // support xtype ctors..
23678 this.tpl = new Roo.factory(this.tpl, Roo);
23682 this.tpl.compile();
23689 * @event beforeclick
23690 * Fires before a click is processed. Returns false to cancel the default action.
23691 * @param {Roo.View} this
23692 * @param {Number} index The index of the target node
23693 * @param {HTMLElement} node The target node
23694 * @param {Roo.EventObject} e The raw event object
23696 "beforeclick" : true,
23699 * Fires when a template node is clicked.
23700 * @param {Roo.View} this
23701 * @param {Number} index The index of the target node
23702 * @param {HTMLElement} node The target node
23703 * @param {Roo.EventObject} e The raw event object
23708 * Fires when a template node is double clicked.
23709 * @param {Roo.View} this
23710 * @param {Number} index The index of the target node
23711 * @param {HTMLElement} node The target node
23712 * @param {Roo.EventObject} e The raw event object
23716 * @event contextmenu
23717 * Fires when a template node is right clicked.
23718 * @param {Roo.View} this
23719 * @param {Number} index The index of the target node
23720 * @param {HTMLElement} node The target node
23721 * @param {Roo.EventObject} e The raw event object
23723 "contextmenu" : true,
23725 * @event selectionchange
23726 * Fires when the selected nodes change.
23727 * @param {Roo.View} this
23728 * @param {Array} selections Array of the selected nodes
23730 "selectionchange" : true,
23733 * @event beforeselect
23734 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23735 * @param {Roo.View} this
23736 * @param {HTMLElement} node The node to be selected
23737 * @param {Array} selections Array of currently selected nodes
23739 "beforeselect" : true,
23741 * @event preparedata
23742 * Fires on every row to render, to allow you to change the data.
23743 * @param {Roo.View} this
23744 * @param {Object} data to be rendered (change this)
23746 "preparedata" : true
23750 "click": this.onClick,
23751 "dblclick": this.onDblClick,
23752 "contextmenu": this.onContextMenu,
23756 this.selections = [];
23758 this.cmp = new Roo.CompositeElementLite([]);
23760 this.store = Roo.factory(this.store, Roo.data);
23761 this.setStore(this.store, true);
23763 Roo.View.superclass.constructor.call(this);
23766 Roo.extend(Roo.View, Roo.util.Observable, {
23769 * @cfg {Roo.data.Store} store Data store to load data from.
23774 * @cfg {String|Roo.Element} el The container element.
23779 * @cfg {String|Roo.Template} tpl The template used by this View
23783 * @cfg {String} dataName the named area of the template to use as the data area
23784 * Works with domtemplates roo-name="name"
23788 * @cfg {String} selectedClass The css class to add to selected nodes
23790 selectedClass : "x-view-selected",
23792 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23796 * @cfg {Boolean} multiSelect Allow multiple selection
23798 multiSelect : false,
23800 * @cfg {Boolean} singleSelect Allow single selection
23802 singleSelect: false,
23805 * @cfg {Boolean} toggleSelect - selecting
23807 toggleSelect : false,
23810 * Returns the element this view is bound to.
23811 * @return {Roo.Element}
23813 getEl : function(){
23818 * Refreshes the view.
23820 refresh : function(){
23823 // if we are using something like 'domtemplate', then
23824 // the what gets used is:
23825 // t.applySubtemplate(NAME, data, wrapping data..)
23826 // the outer template then get' applied with
23827 // the store 'extra data'
23828 // and the body get's added to the
23829 // roo-name="data" node?
23830 // <span class='roo-tpl-{name}'></span> ?????
23834 this.clearSelections();
23835 this.el.update("");
23837 var records = this.store.getRange();
23838 if(records.length < 1) {
23840 // is this valid?? = should it render a template??
23842 this.el.update(this.emptyText);
23846 if (this.dataName) {
23847 this.el.update(t.apply(this.store.meta)); //????
23848 el = this.el.child('.roo-tpl-' + this.dataName);
23851 for(var i = 0, len = records.length; i < len; i++){
23852 var data = this.prepareData(records[i].data, i, records[i]);
23853 this.fireEvent("preparedata", this, data, i, records[i]);
23854 html[html.length] = Roo.util.Format.trim(
23856 t.applySubtemplate(this.dataName, data, this.store.meta) :
23863 el.update(html.join(""));
23864 this.nodes = el.dom.childNodes;
23865 this.updateIndexes(0);
23869 * Function to override to reformat the data that is sent to
23870 * the template for each node.
23871 * DEPRICATED - use the preparedata event handler.
23872 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23873 * a JSON object for an UpdateManager bound view).
23875 prepareData : function(data, index, record)
23877 this.fireEvent("preparedata", this, data, index, record);
23881 onUpdate : function(ds, record){
23882 this.clearSelections();
23883 var index = this.store.indexOf(record);
23884 var n = this.nodes[index];
23885 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
23886 n.parentNode.removeChild(n);
23887 this.updateIndexes(index, index);
23893 onAdd : function(ds, records, index)
23895 this.clearSelections();
23896 if(this.nodes.length == 0){
23900 var n = this.nodes[index];
23901 for(var i = 0, len = records.length; i < len; i++){
23902 var d = this.prepareData(records[i].data, i, records[i]);
23904 this.tpl.insertBefore(n, d);
23907 this.tpl.append(this.el, d);
23910 this.updateIndexes(index);
23913 onRemove : function(ds, record, index){
23914 this.clearSelections();
23915 var el = this.dataName ?
23916 this.el.child('.roo-tpl-' + this.dataName) :
23918 el.dom.removeChild(this.nodes[index]);
23919 this.updateIndexes(index);
23923 * Refresh an individual node.
23924 * @param {Number} index
23926 refreshNode : function(index){
23927 this.onUpdate(this.store, this.store.getAt(index));
23930 updateIndexes : function(startIndex, endIndex){
23931 var ns = this.nodes;
23932 startIndex = startIndex || 0;
23933 endIndex = endIndex || ns.length - 1;
23934 for(var i = startIndex; i <= endIndex; i++){
23935 ns[i].nodeIndex = i;
23940 * Changes the data store this view uses and refresh the view.
23941 * @param {Store} store
23943 setStore : function(store, initial){
23944 if(!initial && this.store){
23945 this.store.un("datachanged", this.refresh);
23946 this.store.un("add", this.onAdd);
23947 this.store.un("remove", this.onRemove);
23948 this.store.un("update", this.onUpdate);
23949 this.store.un("clear", this.refresh);
23953 store.on("datachanged", this.refresh, this);
23954 store.on("add", this.onAdd, this);
23955 store.on("remove", this.onRemove, this);
23956 store.on("update", this.onUpdate, this);
23957 store.on("clear", this.refresh, this);
23966 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23967 * @param {HTMLElement} node
23968 * @return {HTMLElement} The template node
23970 findItemFromChild : function(node){
23971 var el = this.dataName ?
23972 this.el.child('.roo-tpl-' + this.dataName,true) :
23975 if(!node || node.parentNode == el){
23978 var p = node.parentNode;
23979 while(p && p != el){
23980 if(p.parentNode == el){
23989 onClick : function(e){
23990 var item = this.findItemFromChild(e.getTarget());
23992 var index = this.indexOf(item);
23993 if(this.onItemClick(item, index, e) !== false){
23994 this.fireEvent("click", this, index, item, e);
23997 this.clearSelections();
24002 onContextMenu : function(e){
24003 var item = this.findItemFromChild(e.getTarget());
24005 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24010 onDblClick : function(e){
24011 var item = this.findItemFromChild(e.getTarget());
24013 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24017 onItemClick : function(item, index, e)
24019 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24022 if (this.toggleSelect) {
24023 var m = this.isSelected(item) ? 'unselect' : 'select';
24026 _t[m](item, true, false);
24029 if(this.multiSelect || this.singleSelect){
24030 if(this.multiSelect && e.shiftKey && this.lastSelection){
24031 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24033 this.select(item, this.multiSelect && e.ctrlKey);
24034 this.lastSelection = item;
24036 e.preventDefault();
24042 * Get the number of selected nodes.
24045 getSelectionCount : function(){
24046 return this.selections.length;
24050 * Get the currently selected nodes.
24051 * @return {Array} An array of HTMLElements
24053 getSelectedNodes : function(){
24054 return this.selections;
24058 * Get the indexes of the selected nodes.
24061 getSelectedIndexes : function(){
24062 var indexes = [], s = this.selections;
24063 for(var i = 0, len = s.length; i < len; i++){
24064 indexes.push(s[i].nodeIndex);
24070 * Clear all selections
24071 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24073 clearSelections : function(suppressEvent){
24074 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24075 this.cmp.elements = this.selections;
24076 this.cmp.removeClass(this.selectedClass);
24077 this.selections = [];
24078 if(!suppressEvent){
24079 this.fireEvent("selectionchange", this, this.selections);
24085 * Returns true if the passed node is selected
24086 * @param {HTMLElement/Number} node The node or node index
24087 * @return {Boolean}
24089 isSelected : function(node){
24090 var s = this.selections;
24094 node = this.getNode(node);
24095 return s.indexOf(node) !== -1;
24100 * @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
24101 * @param {Boolean} keepExisting (optional) true to keep existing selections
24102 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24104 select : function(nodeInfo, keepExisting, suppressEvent){
24105 if(nodeInfo instanceof Array){
24107 this.clearSelections(true);
24109 for(var i = 0, len = nodeInfo.length; i < len; i++){
24110 this.select(nodeInfo[i], true, true);
24114 var node = this.getNode(nodeInfo);
24115 if(!node || this.isSelected(node)){
24116 return; // already selected.
24119 this.clearSelections(true);
24121 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24122 Roo.fly(node).addClass(this.selectedClass);
24123 this.selections.push(node);
24124 if(!suppressEvent){
24125 this.fireEvent("selectionchange", this, this.selections);
24133 * @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
24134 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24135 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24137 unselect : function(nodeInfo, keepExisting, suppressEvent)
24139 if(nodeInfo instanceof Array){
24140 Roo.each(this.selections, function(s) {
24141 this.unselect(s, nodeInfo);
24145 var node = this.getNode(nodeInfo);
24146 if(!node || !this.isSelected(node)){
24147 Roo.log("not selected");
24148 return; // not selected.
24152 Roo.each(this.selections, function(s) {
24154 Roo.fly(node).removeClass(this.selectedClass);
24161 this.selections= ns;
24162 this.fireEvent("selectionchange", this, this.selections);
24166 * Gets a template node.
24167 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24168 * @return {HTMLElement} The node or null if it wasn't found
24170 getNode : function(nodeInfo){
24171 if(typeof nodeInfo == "string"){
24172 return document.getElementById(nodeInfo);
24173 }else if(typeof nodeInfo == "number"){
24174 return this.nodes[nodeInfo];
24180 * Gets a range template nodes.
24181 * @param {Number} startIndex
24182 * @param {Number} endIndex
24183 * @return {Array} An array of nodes
24185 getNodes : function(start, end){
24186 var ns = this.nodes;
24187 start = start || 0;
24188 end = typeof end == "undefined" ? ns.length - 1 : end;
24191 for(var i = start; i <= end; i++){
24195 for(var i = start; i >= end; i--){
24203 * Finds the index of the passed node
24204 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24205 * @return {Number} The index of the node or -1
24207 indexOf : function(node){
24208 node = this.getNode(node);
24209 if(typeof node.nodeIndex == "number"){
24210 return node.nodeIndex;
24212 var ns = this.nodes;
24213 for(var i = 0, len = ns.length; i < len; i++){
24223 * Ext JS Library 1.1.1
24224 * Copyright(c) 2006-2007, Ext JS, LLC.
24226 * Originally Released Under LGPL - original licence link has changed is not relivant.
24229 * <script type="text/javascript">
24233 * @class Roo.JsonView
24234 * @extends Roo.View
24235 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24237 var view = new Roo.JsonView({
24238 container: "my-element",
24239 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24244 // listen for node click?
24245 view.on("click", function(vw, index, node, e){
24246 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24249 // direct load of JSON data
24250 view.load("foobar.php");
24252 // Example from my blog list
24253 var tpl = new Roo.Template(
24254 '<div class="entry">' +
24255 '<a class="entry-title" href="{link}">{title}</a>' +
24256 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24257 "</div><hr />"
24260 var moreView = new Roo.JsonView({
24261 container : "entry-list",
24265 moreView.on("beforerender", this.sortEntries, this);
24267 url: "/blog/get-posts.php",
24268 params: "allposts=true",
24269 text: "Loading Blog Entries..."
24273 * Note: old code is supported with arguments : (container, template, config)
24277 * Create a new JsonView
24279 * @param {Object} config The config object
24282 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24285 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24287 var um = this.el.getUpdateManager();
24288 um.setRenderer(this);
24289 um.on("update", this.onLoad, this);
24290 um.on("failure", this.onLoadException, this);
24293 * @event beforerender
24294 * Fires before rendering of the downloaded JSON data.
24295 * @param {Roo.JsonView} this
24296 * @param {Object} data The JSON data loaded
24300 * Fires when data is loaded.
24301 * @param {Roo.JsonView} this
24302 * @param {Object} data The JSON data loaded
24303 * @param {Object} response The raw Connect response object
24306 * @event loadexception
24307 * Fires when loading fails.
24308 * @param {Roo.JsonView} this
24309 * @param {Object} response The raw Connect response object
24312 'beforerender' : true,
24314 'loadexception' : true
24317 Roo.extend(Roo.JsonView, Roo.View, {
24319 * @type {String} The root property in the loaded JSON object that contains the data
24324 * Refreshes the view.
24326 refresh : function(){
24327 this.clearSelections();
24328 this.el.update("");
24330 var o = this.jsonData;
24331 if(o && o.length > 0){
24332 for(var i = 0, len = o.length; i < len; i++){
24333 var data = this.prepareData(o[i], i, o);
24334 html[html.length] = this.tpl.apply(data);
24337 html.push(this.emptyText);
24339 this.el.update(html.join(""));
24340 this.nodes = this.el.dom.childNodes;
24341 this.updateIndexes(0);
24345 * 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.
24346 * @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:
24349 url: "your-url.php",
24350 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24351 callback: yourFunction,
24352 scope: yourObject, //(optional scope)
24355 text: "Loading...",
24360 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24361 * 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.
24362 * @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}
24363 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24364 * @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.
24367 var um = this.el.getUpdateManager();
24368 um.update.apply(um, arguments);
24371 render : function(el, response){
24372 this.clearSelections();
24373 this.el.update("");
24376 o = Roo.util.JSON.decode(response.responseText);
24379 o = o[this.jsonRoot];
24384 * The current JSON data or null
24387 this.beforeRender();
24392 * Get the number of records in the current JSON dataset
24395 getCount : function(){
24396 return this.jsonData ? this.jsonData.length : 0;
24400 * Returns the JSON object for the specified node(s)
24401 * @param {HTMLElement/Array} node The node or an array of nodes
24402 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24403 * you get the JSON object for the node
24405 getNodeData : function(node){
24406 if(node instanceof Array){
24408 for(var i = 0, len = node.length; i < len; i++){
24409 data.push(this.getNodeData(node[i]));
24413 return this.jsonData[this.indexOf(node)] || null;
24416 beforeRender : function(){
24417 this.snapshot = this.jsonData;
24419 this.sort.apply(this, this.sortInfo);
24421 this.fireEvent("beforerender", this, this.jsonData);
24424 onLoad : function(el, o){
24425 this.fireEvent("load", this, this.jsonData, o);
24428 onLoadException : function(el, o){
24429 this.fireEvent("loadexception", this, o);
24433 * Filter the data by a specific property.
24434 * @param {String} property A property on your JSON objects
24435 * @param {String/RegExp} value Either string that the property values
24436 * should start with, or a RegExp to test against the property
24438 filter : function(property, value){
24441 var ss = this.snapshot;
24442 if(typeof value == "string"){
24443 var vlen = value.length;
24445 this.clearFilter();
24448 value = value.toLowerCase();
24449 for(var i = 0, len = ss.length; i < len; i++){
24451 if(o[property].substr(0, vlen).toLowerCase() == value){
24455 } else if(value.exec){ // regex?
24456 for(var i = 0, len = ss.length; i < len; i++){
24458 if(value.test(o[property])){
24465 this.jsonData = data;
24471 * Filter by a function. The passed function will be called with each
24472 * object in the current dataset. If the function returns true the value is kept,
24473 * otherwise it is filtered.
24474 * @param {Function} fn
24475 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24477 filterBy : function(fn, scope){
24480 var ss = this.snapshot;
24481 for(var i = 0, len = ss.length; i < len; i++){
24483 if(fn.call(scope || this, o)){
24487 this.jsonData = data;
24493 * Clears the current filter.
24495 clearFilter : function(){
24496 if(this.snapshot && this.jsonData != this.snapshot){
24497 this.jsonData = this.snapshot;
24504 * Sorts the data for this view and refreshes it.
24505 * @param {String} property A property on your JSON objects to sort on
24506 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24507 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24509 sort : function(property, dir, sortType){
24510 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24513 var dsc = dir && dir.toLowerCase() == "desc";
24514 var f = function(o1, o2){
24515 var v1 = sortType ? sortType(o1[p]) : o1[p];
24516 var v2 = sortType ? sortType(o2[p]) : o2[p];
24519 return dsc ? +1 : -1;
24520 } else if(v1 > v2){
24521 return dsc ? -1 : +1;
24526 this.jsonData.sort(f);
24528 if(this.jsonData != this.snapshot){
24529 this.snapshot.sort(f);
24535 * Ext JS Library 1.1.1
24536 * Copyright(c) 2006-2007, Ext JS, LLC.
24538 * Originally Released Under LGPL - original licence link has changed is not relivant.
24541 * <script type="text/javascript">
24546 * @class Roo.ColorPalette
24547 * @extends Roo.Component
24548 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24549 * Here's an example of typical usage:
24551 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24552 cp.render('my-div');
24554 cp.on('select', function(palette, selColor){
24555 // do something with selColor
24559 * Create a new ColorPalette
24560 * @param {Object} config The config object
24562 Roo.ColorPalette = function(config){
24563 Roo.ColorPalette.superclass.constructor.call(this, config);
24567 * Fires when a color is selected
24568 * @param {ColorPalette} this
24569 * @param {String} color The 6-digit color hex code (without the # symbol)
24575 this.on("select", this.handler, this.scope, true);
24578 Roo.extend(Roo.ColorPalette, Roo.Component, {
24580 * @cfg {String} itemCls
24581 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24583 itemCls : "x-color-palette",
24585 * @cfg {String} value
24586 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24587 * the hex codes are case-sensitive.
24590 clickEvent:'click',
24592 ctype: "Roo.ColorPalette",
24595 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24597 allowReselect : false,
24600 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24601 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24602 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24603 * of colors with the width setting until the box is symmetrical.</p>
24604 * <p>You can override individual colors if needed:</p>
24606 var cp = new Roo.ColorPalette();
24607 cp.colors[0] = "FF0000"; // change the first box to red
24610 Or you can provide a custom array of your own for complete control:
24612 var cp = new Roo.ColorPalette();
24613 cp.colors = ["000000", "993300", "333300"];
24618 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24619 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24620 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24621 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24622 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24626 onRender : function(container, position){
24627 var t = new Roo.MasterTemplate(
24628 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24630 var c = this.colors;
24631 for(var i = 0, len = c.length; i < len; i++){
24634 var el = document.createElement("div");
24635 el.className = this.itemCls;
24637 container.dom.insertBefore(el, position);
24638 this.el = Roo.get(el);
24639 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24640 if(this.clickEvent != 'click'){
24641 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24646 afterRender : function(){
24647 Roo.ColorPalette.superclass.afterRender.call(this);
24649 var s = this.value;
24656 handleClick : function(e, t){
24657 e.preventDefault();
24658 if(!this.disabled){
24659 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24660 this.select(c.toUpperCase());
24665 * Selects the specified color in the palette (fires the select event)
24666 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24668 select : function(color){
24669 color = color.replace("#", "");
24670 if(color != this.value || this.allowReselect){
24673 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24675 el.child("a.color-"+color).addClass("x-color-palette-sel");
24676 this.value = color;
24677 this.fireEvent("select", this, color);
24682 * Ext JS Library 1.1.1
24683 * Copyright(c) 2006-2007, Ext JS, LLC.
24685 * Originally Released Under LGPL - original licence link has changed is not relivant.
24688 * <script type="text/javascript">
24692 * @class Roo.DatePicker
24693 * @extends Roo.Component
24694 * Simple date picker class.
24696 * Create a new DatePicker
24697 * @param {Object} config The config object
24699 Roo.DatePicker = function(config){
24700 Roo.DatePicker.superclass.constructor.call(this, config);
24702 this.value = config && config.value ?
24703 config.value.clearTime() : new Date().clearTime();
24708 * Fires when a date is selected
24709 * @param {DatePicker} this
24710 * @param {Date} date The selected date
24714 * @event monthchange
24715 * Fires when the displayed month changes
24716 * @param {DatePicker} this
24717 * @param {Date} date The selected month
24719 'monthchange': true
24723 this.on("select", this.handler, this.scope || this);
24725 // build the disabledDatesRE
24726 if(!this.disabledDatesRE && this.disabledDates){
24727 var dd = this.disabledDates;
24729 for(var i = 0; i < dd.length; i++){
24731 if(i != dd.length-1) re += "|";
24733 this.disabledDatesRE = new RegExp(re + ")");
24737 Roo.extend(Roo.DatePicker, Roo.Component, {
24739 * @cfg {String} todayText
24740 * The text to display on the button that selects the current date (defaults to "Today")
24742 todayText : "Today",
24744 * @cfg {String} okText
24745 * The text to display on the ok button
24747 okText : " OK ", //   to give the user extra clicking room
24749 * @cfg {String} cancelText
24750 * The text to display on the cancel button
24752 cancelText : "Cancel",
24754 * @cfg {String} todayTip
24755 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24757 todayTip : "{0} (Spacebar)",
24759 * @cfg {Date} minDate
24760 * Minimum allowable date (JavaScript date object, defaults to null)
24764 * @cfg {Date} maxDate
24765 * Maximum allowable date (JavaScript date object, defaults to null)
24769 * @cfg {String} minText
24770 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24772 minText : "This date is before the minimum date",
24774 * @cfg {String} maxText
24775 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24777 maxText : "This date is after the maximum date",
24779 * @cfg {String} format
24780 * The default date format string which can be overriden for localization support. The format must be
24781 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24785 * @cfg {Array} disabledDays
24786 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24788 disabledDays : null,
24790 * @cfg {String} disabledDaysText
24791 * The tooltip to display when the date falls on a disabled day (defaults to "")
24793 disabledDaysText : "",
24795 * @cfg {RegExp} disabledDatesRE
24796 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24798 disabledDatesRE : null,
24800 * @cfg {String} disabledDatesText
24801 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24803 disabledDatesText : "",
24805 * @cfg {Boolean} constrainToViewport
24806 * True to constrain the date picker to the viewport (defaults to true)
24808 constrainToViewport : true,
24810 * @cfg {Array} monthNames
24811 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24813 monthNames : Date.monthNames,
24815 * @cfg {Array} dayNames
24816 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24818 dayNames : Date.dayNames,
24820 * @cfg {String} nextText
24821 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24823 nextText: 'Next Month (Control+Right)',
24825 * @cfg {String} prevText
24826 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24828 prevText: 'Previous Month (Control+Left)',
24830 * @cfg {String} monthYearText
24831 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24833 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24835 * @cfg {Number} startDay
24836 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24840 * @cfg {Bool} showClear
24841 * Show a clear button (usefull for date form elements that can be blank.)
24847 * Sets the value of the date field
24848 * @param {Date} value The date to set
24850 setValue : function(value){
24851 var old = this.value;
24852 this.value = value.clearTime(true);
24854 this.update(this.value);
24859 * Gets the current selected value of the date field
24860 * @return {Date} The selected date
24862 getValue : function(){
24867 focus : function(){
24869 this.update(this.activeDate);
24874 onRender : function(container, position){
24876 '<table cellspacing="0">',
24877 '<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>',
24878 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24879 var dn = this.dayNames;
24880 for(var i = 0; i < 7; i++){
24881 var d = this.startDay+i;
24885 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24887 m[m.length] = "</tr></thead><tbody><tr>";
24888 for(var i = 0; i < 42; i++) {
24889 if(i % 7 == 0 && i != 0){
24890 m[m.length] = "</tr><tr>";
24892 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24894 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24895 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24897 var el = document.createElement("div");
24898 el.className = "x-date-picker";
24899 el.innerHTML = m.join("");
24901 container.dom.insertBefore(el, position);
24903 this.el = Roo.get(el);
24904 this.eventEl = Roo.get(el.firstChild);
24906 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24907 handler: this.showPrevMonth,
24909 preventDefault:true,
24913 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24914 handler: this.showNextMonth,
24916 preventDefault:true,
24920 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24922 this.monthPicker = this.el.down('div.x-date-mp');
24923 this.monthPicker.enableDisplayMode('block');
24925 var kn = new Roo.KeyNav(this.eventEl, {
24926 "left" : function(e){
24928 this.showPrevMonth() :
24929 this.update(this.activeDate.add("d", -1));
24932 "right" : function(e){
24934 this.showNextMonth() :
24935 this.update(this.activeDate.add("d", 1));
24938 "up" : function(e){
24940 this.showNextYear() :
24941 this.update(this.activeDate.add("d", -7));
24944 "down" : function(e){
24946 this.showPrevYear() :
24947 this.update(this.activeDate.add("d", 7));
24950 "pageUp" : function(e){
24951 this.showNextMonth();
24954 "pageDown" : function(e){
24955 this.showPrevMonth();
24958 "enter" : function(e){
24959 e.stopPropagation();
24966 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24968 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24970 this.el.unselectable();
24972 this.cells = this.el.select("table.x-date-inner tbody td");
24973 this.textNodes = this.el.query("table.x-date-inner tbody span");
24975 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24977 tooltip: this.monthYearText
24980 this.mbtn.on('click', this.showMonthPicker, this);
24981 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24984 var today = (new Date()).dateFormat(this.format);
24986 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24987 if (this.showClear) {
24988 baseTb.add( new Roo.Toolbar.Fill());
24991 text: String.format(this.todayText, today),
24992 tooltip: String.format(this.todayTip, today),
24993 handler: this.selectToday,
24997 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25000 if (this.showClear) {
25002 baseTb.add( new Roo.Toolbar.Fill());
25005 cls: 'x-btn-icon x-btn-clear',
25006 handler: function() {
25008 this.fireEvent("select", this, '');
25018 this.update(this.value);
25021 createMonthPicker : function(){
25022 if(!this.monthPicker.dom.firstChild){
25023 var buf = ['<table border="0" cellspacing="0">'];
25024 for(var i = 0; i < 6; i++){
25026 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25027 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25029 '<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>' :
25030 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25034 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25036 '</button><button type="button" class="x-date-mp-cancel">',
25038 '</button></td></tr>',
25041 this.monthPicker.update(buf.join(''));
25042 this.monthPicker.on('click', this.onMonthClick, this);
25043 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25045 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25046 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25048 this.mpMonths.each(function(m, a, i){
25051 m.dom.xmonth = 5 + Math.round(i * .5);
25053 m.dom.xmonth = Math.round((i-1) * .5);
25059 showMonthPicker : function(){
25060 this.createMonthPicker();
25061 var size = this.el.getSize();
25062 this.monthPicker.setSize(size);
25063 this.monthPicker.child('table').setSize(size);
25065 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25066 this.updateMPMonth(this.mpSelMonth);
25067 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25068 this.updateMPYear(this.mpSelYear);
25070 this.monthPicker.slideIn('t', {duration:.2});
25073 updateMPYear : function(y){
25075 var ys = this.mpYears.elements;
25076 for(var i = 1; i <= 10; i++){
25077 var td = ys[i-1], y2;
25079 y2 = y + Math.round(i * .5);
25080 td.firstChild.innerHTML = y2;
25083 y2 = y - (5-Math.round(i * .5));
25084 td.firstChild.innerHTML = y2;
25087 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25091 updateMPMonth : function(sm){
25092 this.mpMonths.each(function(m, a, i){
25093 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25097 selectMPMonth: function(m){
25101 onMonthClick : function(e, t){
25103 var el = new Roo.Element(t), pn;
25104 if(el.is('button.x-date-mp-cancel')){
25105 this.hideMonthPicker();
25107 else if(el.is('button.x-date-mp-ok')){
25108 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25109 this.hideMonthPicker();
25111 else if(pn = el.up('td.x-date-mp-month', 2)){
25112 this.mpMonths.removeClass('x-date-mp-sel');
25113 pn.addClass('x-date-mp-sel');
25114 this.mpSelMonth = pn.dom.xmonth;
25116 else if(pn = el.up('td.x-date-mp-year', 2)){
25117 this.mpYears.removeClass('x-date-mp-sel');
25118 pn.addClass('x-date-mp-sel');
25119 this.mpSelYear = pn.dom.xyear;
25121 else if(el.is('a.x-date-mp-prev')){
25122 this.updateMPYear(this.mpyear-10);
25124 else if(el.is('a.x-date-mp-next')){
25125 this.updateMPYear(this.mpyear+10);
25129 onMonthDblClick : function(e, t){
25131 var el = new Roo.Element(t), pn;
25132 if(pn = el.up('td.x-date-mp-month', 2)){
25133 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25134 this.hideMonthPicker();
25136 else if(pn = el.up('td.x-date-mp-year', 2)){
25137 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25138 this.hideMonthPicker();
25142 hideMonthPicker : function(disableAnim){
25143 if(this.monthPicker){
25144 if(disableAnim === true){
25145 this.monthPicker.hide();
25147 this.monthPicker.slideOut('t', {duration:.2});
25153 showPrevMonth : function(e){
25154 this.update(this.activeDate.add("mo", -1));
25158 showNextMonth : function(e){
25159 this.update(this.activeDate.add("mo", 1));
25163 showPrevYear : function(){
25164 this.update(this.activeDate.add("y", -1));
25168 showNextYear : function(){
25169 this.update(this.activeDate.add("y", 1));
25173 handleMouseWheel : function(e){
25174 var delta = e.getWheelDelta();
25176 this.showPrevMonth();
25178 } else if(delta < 0){
25179 this.showNextMonth();
25185 handleDateClick : function(e, t){
25187 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25188 this.setValue(new Date(t.dateValue));
25189 this.fireEvent("select", this, this.value);
25194 selectToday : function(){
25195 this.setValue(new Date().clearTime());
25196 this.fireEvent("select", this, this.value);
25200 update : function(date)
25202 var vd = this.activeDate;
25203 this.activeDate = date;
25205 var t = date.getTime();
25206 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25207 this.cells.removeClass("x-date-selected");
25208 this.cells.each(function(c){
25209 if(c.dom.firstChild.dateValue == t){
25210 c.addClass("x-date-selected");
25211 setTimeout(function(){
25212 try{c.dom.firstChild.focus();}catch(e){}
25221 var days = date.getDaysInMonth();
25222 var firstOfMonth = date.getFirstDateOfMonth();
25223 var startingPos = firstOfMonth.getDay()-this.startDay;
25225 if(startingPos <= this.startDay){
25229 var pm = date.add("mo", -1);
25230 var prevStart = pm.getDaysInMonth()-startingPos;
25232 var cells = this.cells.elements;
25233 var textEls = this.textNodes;
25234 days += startingPos;
25236 // convert everything to numbers so it's fast
25237 var day = 86400000;
25238 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25239 var today = new Date().clearTime().getTime();
25240 var sel = date.clearTime().getTime();
25241 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25242 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25243 var ddMatch = this.disabledDatesRE;
25244 var ddText = this.disabledDatesText;
25245 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25246 var ddaysText = this.disabledDaysText;
25247 var format = this.format;
25249 var setCellClass = function(cal, cell){
25251 var t = d.getTime();
25252 cell.firstChild.dateValue = t;
25254 cell.className += " x-date-today";
25255 cell.title = cal.todayText;
25258 cell.className += " x-date-selected";
25259 setTimeout(function(){
25260 try{cell.firstChild.focus();}catch(e){}
25265 cell.className = " x-date-disabled";
25266 cell.title = cal.minText;
25270 cell.className = " x-date-disabled";
25271 cell.title = cal.maxText;
25275 if(ddays.indexOf(d.getDay()) != -1){
25276 cell.title = ddaysText;
25277 cell.className = " x-date-disabled";
25280 if(ddMatch && format){
25281 var fvalue = d.dateFormat(format);
25282 if(ddMatch.test(fvalue)){
25283 cell.title = ddText.replace("%0", fvalue);
25284 cell.className = " x-date-disabled";
25290 for(; i < startingPos; i++) {
25291 textEls[i].innerHTML = (++prevStart);
25292 d.setDate(d.getDate()+1);
25293 cells[i].className = "x-date-prevday";
25294 setCellClass(this, cells[i]);
25296 for(; i < days; i++){
25297 intDay = i - startingPos + 1;
25298 textEls[i].innerHTML = (intDay);
25299 d.setDate(d.getDate()+1);
25300 cells[i].className = "x-date-active";
25301 setCellClass(this, cells[i]);
25304 for(; i < 42; i++) {
25305 textEls[i].innerHTML = (++extraDays);
25306 d.setDate(d.getDate()+1);
25307 cells[i].className = "x-date-nextday";
25308 setCellClass(this, cells[i]);
25311 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25312 this.fireEvent('monthchange', this, date);
25314 if(!this.internalRender){
25315 var main = this.el.dom.firstChild;
25316 var w = main.offsetWidth;
25317 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25318 Roo.fly(main).setWidth(w);
25319 this.internalRender = true;
25320 // opera does not respect the auto grow header center column
25321 // then, after it gets a width opera refuses to recalculate
25322 // without a second pass
25323 if(Roo.isOpera && !this.secondPass){
25324 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25325 this.secondPass = true;
25326 this.update.defer(10, this, [date]);
25334 * Ext JS Library 1.1.1
25335 * Copyright(c) 2006-2007, Ext JS, LLC.
25337 * Originally Released Under LGPL - original licence link has changed is not relivant.
25340 * <script type="text/javascript">
25343 * @class Roo.TabPanel
25344 * @extends Roo.util.Observable
25345 * A lightweight tab container.
25349 // basic tabs 1, built from existing content
25350 var tabs = new Roo.TabPanel("tabs1");
25351 tabs.addTab("script", "View Script");
25352 tabs.addTab("markup", "View Markup");
25353 tabs.activate("script");
25355 // more advanced tabs, built from javascript
25356 var jtabs = new Roo.TabPanel("jtabs");
25357 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25359 // set up the UpdateManager
25360 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25361 var updater = tab2.getUpdateManager();
25362 updater.setDefaultUrl("ajax1.htm");
25363 tab2.on('activate', updater.refresh, updater, true);
25365 // Use setUrl for Ajax loading
25366 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25367 tab3.setUrl("ajax2.htm", null, true);
25370 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25373 jtabs.activate("jtabs-1");
25376 * Create a new TabPanel.
25377 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25378 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25380 Roo.TabPanel = function(container, config){
25382 * The container element for this TabPanel.
25383 * @type Roo.Element
25385 this.el = Roo.get(container, true);
25387 if(typeof config == "boolean"){
25388 this.tabPosition = config ? "bottom" : "top";
25390 Roo.apply(this, config);
25393 if(this.tabPosition == "bottom"){
25394 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25395 this.el.addClass("x-tabs-bottom");
25397 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25398 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25399 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25401 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25403 if(this.tabPosition != "bottom"){
25404 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25405 * @type Roo.Element
25407 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25408 this.el.addClass("x-tabs-top");
25412 this.bodyEl.setStyle("position", "relative");
25414 this.active = null;
25415 this.activateDelegate = this.activate.createDelegate(this);
25420 * Fires when the active tab changes
25421 * @param {Roo.TabPanel} this
25422 * @param {Roo.TabPanelItem} activePanel The new active tab
25426 * @event beforetabchange
25427 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25428 * @param {Roo.TabPanel} this
25429 * @param {Object} e Set cancel to true on this object to cancel the tab change
25430 * @param {Roo.TabPanelItem} tab The tab being changed to
25432 "beforetabchange" : true
25435 Roo.EventManager.onWindowResize(this.onResize, this);
25436 this.cpad = this.el.getPadding("lr");
25437 this.hiddenCount = 0;
25440 // toolbar on the tabbar support...
25441 if (this.toolbar) {
25442 var tcfg = this.toolbar;
25443 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25444 this.toolbar = new Roo.Toolbar(tcfg);
25445 if (Roo.isSafari) {
25446 var tbl = tcfg.container.child('table', true);
25447 tbl.setAttribute('width', '100%');
25454 Roo.TabPanel.superclass.constructor.call(this);
25457 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25459 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25461 tabPosition : "top",
25463 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25465 currentTabWidth : 0,
25467 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25471 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25475 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25477 preferredTabWidth : 175,
25479 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25481 resizeTabs : false,
25483 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25485 monitorResize : true,
25487 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25492 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25493 * @param {String} id The id of the div to use <b>or create</b>
25494 * @param {String} text The text for the tab
25495 * @param {String} content (optional) Content to put in the TabPanelItem body
25496 * @param {Boolean} closable (optional) True to create a close icon on the tab
25497 * @return {Roo.TabPanelItem} The created TabPanelItem
25499 addTab : function(id, text, content, closable){
25500 var item = new Roo.TabPanelItem(this, id, text, closable);
25501 this.addTabItem(item);
25503 item.setContent(content);
25509 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25510 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25511 * @return {Roo.TabPanelItem}
25513 getTab : function(id){
25514 return this.items[id];
25518 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25519 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25521 hideTab : function(id){
25522 var t = this.items[id];
25525 this.hiddenCount++;
25526 this.autoSizeTabs();
25531 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25532 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25534 unhideTab : function(id){
25535 var t = this.items[id];
25537 t.setHidden(false);
25538 this.hiddenCount--;
25539 this.autoSizeTabs();
25544 * Adds an existing {@link Roo.TabPanelItem}.
25545 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25547 addTabItem : function(item){
25548 this.items[item.id] = item;
25549 this.items.push(item);
25550 if(this.resizeTabs){
25551 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25552 this.autoSizeTabs();
25559 * Removes a {@link Roo.TabPanelItem}.
25560 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25562 removeTab : function(id){
25563 var items = this.items;
25564 var tab = items[id];
25565 if(!tab) { return; }
25566 var index = items.indexOf(tab);
25567 if(this.active == tab && items.length > 1){
25568 var newTab = this.getNextAvailable(index);
25573 this.stripEl.dom.removeChild(tab.pnode.dom);
25574 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25575 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25577 items.splice(index, 1);
25578 delete this.items[tab.id];
25579 tab.fireEvent("close", tab);
25580 tab.purgeListeners();
25581 this.autoSizeTabs();
25584 getNextAvailable : function(start){
25585 var items = this.items;
25587 // look for a next tab that will slide over to
25588 // replace the one being removed
25589 while(index < items.length){
25590 var item = items[++index];
25591 if(item && !item.isHidden()){
25595 // if one isn't found select the previous tab (on the left)
25598 var item = items[--index];
25599 if(item && !item.isHidden()){
25607 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25608 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25610 disableTab : function(id){
25611 var tab = this.items[id];
25612 if(tab && this.active != tab){
25618 * Enables a {@link Roo.TabPanelItem} that is disabled.
25619 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25621 enableTab : function(id){
25622 var tab = this.items[id];
25627 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25628 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25629 * @return {Roo.TabPanelItem} The TabPanelItem.
25631 activate : function(id){
25632 var tab = this.items[id];
25636 if(tab == this.active || tab.disabled){
25640 this.fireEvent("beforetabchange", this, e, tab);
25641 if(e.cancel !== true && !tab.disabled){
25643 this.active.hide();
25645 this.active = this.items[id];
25646 this.active.show();
25647 this.fireEvent("tabchange", this, this.active);
25653 * Gets the active {@link Roo.TabPanelItem}.
25654 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25656 getActiveTab : function(){
25657 return this.active;
25661 * Updates the tab body element to fit the height of the container element
25662 * for overflow scrolling
25663 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25665 syncHeight : function(targetHeight){
25666 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25667 var bm = this.bodyEl.getMargins();
25668 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25669 this.bodyEl.setHeight(newHeight);
25673 onResize : function(){
25674 if(this.monitorResize){
25675 this.autoSizeTabs();
25680 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25682 beginUpdate : function(){
25683 this.updating = true;
25687 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25689 endUpdate : function(){
25690 this.updating = false;
25691 this.autoSizeTabs();
25695 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25697 autoSizeTabs : function(){
25698 var count = this.items.length;
25699 var vcount = count - this.hiddenCount;
25700 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25701 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25702 var availWidth = Math.floor(w / vcount);
25703 var b = this.stripBody;
25704 if(b.getWidth() > w){
25705 var tabs = this.items;
25706 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25707 if(availWidth < this.minTabWidth){
25708 /*if(!this.sleft){ // incomplete scrolling code
25709 this.createScrollButtons();
25712 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25715 if(this.currentTabWidth < this.preferredTabWidth){
25716 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25722 * Returns the number of tabs in this TabPanel.
25725 getCount : function(){
25726 return this.items.length;
25730 * Resizes all the tabs to the passed width
25731 * @param {Number} The new width
25733 setTabWidth : function(width){
25734 this.currentTabWidth = width;
25735 for(var i = 0, len = this.items.length; i < len; i++) {
25736 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25741 * Destroys this TabPanel
25742 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25744 destroy : function(removeEl){
25745 Roo.EventManager.removeResizeListener(this.onResize, this);
25746 for(var i = 0, len = this.items.length; i < len; i++){
25747 this.items[i].purgeListeners();
25749 if(removeEl === true){
25750 this.el.update("");
25757 * @class Roo.TabPanelItem
25758 * @extends Roo.util.Observable
25759 * Represents an individual item (tab plus body) in a TabPanel.
25760 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25761 * @param {String} id The id of this TabPanelItem
25762 * @param {String} text The text for the tab of this TabPanelItem
25763 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25765 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25767 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25768 * @type Roo.TabPanel
25770 this.tabPanel = tabPanel;
25772 * The id for this TabPanelItem
25777 this.disabled = false;
25781 this.loaded = false;
25782 this.closable = closable;
25785 * The body element for this TabPanelItem.
25786 * @type Roo.Element
25788 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25789 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25790 this.bodyEl.setStyle("display", "block");
25791 this.bodyEl.setStyle("zoom", "1");
25794 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25796 this.el = Roo.get(els.el, true);
25797 this.inner = Roo.get(els.inner, true);
25798 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25799 this.pnode = Roo.get(els.el.parentNode, true);
25800 this.el.on("mousedown", this.onTabMouseDown, this);
25801 this.el.on("click", this.onTabClick, this);
25804 var c = Roo.get(els.close, true);
25805 c.dom.title = this.closeText;
25806 c.addClassOnOver("close-over");
25807 c.on("click", this.closeClick, this);
25813 * Fires when this tab becomes the active tab.
25814 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25815 * @param {Roo.TabPanelItem} this
25819 * @event beforeclose
25820 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25821 * @param {Roo.TabPanelItem} this
25822 * @param {Object} e Set cancel to true on this object to cancel the close.
25824 "beforeclose": true,
25827 * Fires when this tab is closed.
25828 * @param {Roo.TabPanelItem} this
25832 * @event deactivate
25833 * Fires when this tab is no longer the active tab.
25834 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25835 * @param {Roo.TabPanelItem} this
25837 "deactivate" : true
25839 this.hidden = false;
25841 Roo.TabPanelItem.superclass.constructor.call(this);
25844 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25845 purgeListeners : function(){
25846 Roo.util.Observable.prototype.purgeListeners.call(this);
25847 this.el.removeAllListeners();
25850 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25853 this.pnode.addClass("on");
25856 this.tabPanel.stripWrap.repaint();
25858 this.fireEvent("activate", this.tabPanel, this);
25862 * Returns true if this tab is the active tab.
25863 * @return {Boolean}
25865 isActive : function(){
25866 return this.tabPanel.getActiveTab() == this;
25870 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25873 this.pnode.removeClass("on");
25875 this.fireEvent("deactivate", this.tabPanel, this);
25878 hideAction : function(){
25879 this.bodyEl.hide();
25880 this.bodyEl.setStyle("position", "absolute");
25881 this.bodyEl.setLeft("-20000px");
25882 this.bodyEl.setTop("-20000px");
25885 showAction : function(){
25886 this.bodyEl.setStyle("position", "relative");
25887 this.bodyEl.setTop("");
25888 this.bodyEl.setLeft("");
25889 this.bodyEl.show();
25893 * Set the tooltip for the tab.
25894 * @param {String} tooltip The tab's tooltip
25896 setTooltip : function(text){
25897 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25898 this.textEl.dom.qtip = text;
25899 this.textEl.dom.removeAttribute('title');
25901 this.textEl.dom.title = text;
25905 onTabClick : function(e){
25906 e.preventDefault();
25907 this.tabPanel.activate(this.id);
25910 onTabMouseDown : function(e){
25911 e.preventDefault();
25912 this.tabPanel.activate(this.id);
25915 getWidth : function(){
25916 return this.inner.getWidth();
25919 setWidth : function(width){
25920 var iwidth = width - this.pnode.getPadding("lr");
25921 this.inner.setWidth(iwidth);
25922 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25923 this.pnode.setWidth(width);
25927 * Show or hide the tab
25928 * @param {Boolean} hidden True to hide or false to show.
25930 setHidden : function(hidden){
25931 this.hidden = hidden;
25932 this.pnode.setStyle("display", hidden ? "none" : "");
25936 * Returns true if this tab is "hidden"
25937 * @return {Boolean}
25939 isHidden : function(){
25940 return this.hidden;
25944 * Returns the text for this tab
25947 getText : function(){
25951 autoSize : function(){
25952 //this.el.beginMeasure();
25953 this.textEl.setWidth(1);
25954 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25955 //this.el.endMeasure();
25959 * Sets the text for the tab (Note: this also sets the tooltip text)
25960 * @param {String} text The tab's text and tooltip
25962 setText : function(text){
25964 this.textEl.update(text);
25965 this.setTooltip(text);
25966 if(!this.tabPanel.resizeTabs){
25971 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25973 activate : function(){
25974 this.tabPanel.activate(this.id);
25978 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25980 disable : function(){
25981 if(this.tabPanel.active != this){
25982 this.disabled = true;
25983 this.pnode.addClass("disabled");
25988 * Enables this TabPanelItem if it was previously disabled.
25990 enable : function(){
25991 this.disabled = false;
25992 this.pnode.removeClass("disabled");
25996 * Sets the content for this TabPanelItem.
25997 * @param {String} content The content
25998 * @param {Boolean} loadScripts true to look for and load scripts
26000 setContent : function(content, loadScripts){
26001 this.bodyEl.update(content, loadScripts);
26005 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26006 * @return {Roo.UpdateManager} The UpdateManager
26008 getUpdateManager : function(){
26009 return this.bodyEl.getUpdateManager();
26013 * Set a URL to be used to load the content for this TabPanelItem.
26014 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26015 * @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)
26016 * @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)
26017 * @return {Roo.UpdateManager} The UpdateManager
26019 setUrl : function(url, params, loadOnce){
26020 if(this.refreshDelegate){
26021 this.un('activate', this.refreshDelegate);
26023 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26024 this.on("activate", this.refreshDelegate);
26025 return this.bodyEl.getUpdateManager();
26029 _handleRefresh : function(url, params, loadOnce){
26030 if(!loadOnce || !this.loaded){
26031 var updater = this.bodyEl.getUpdateManager();
26032 updater.update(url, params, this._setLoaded.createDelegate(this));
26037 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26038 * Will fail silently if the setUrl method has not been called.
26039 * This does not activate the panel, just updates its content.
26041 refresh : function(){
26042 if(this.refreshDelegate){
26043 this.loaded = false;
26044 this.refreshDelegate();
26049 _setLoaded : function(){
26050 this.loaded = true;
26054 closeClick : function(e){
26057 this.fireEvent("beforeclose", this, o);
26058 if(o.cancel !== true){
26059 this.tabPanel.removeTab(this.id);
26063 * The text displayed in the tooltip for the close icon.
26066 closeText : "Close this tab"
26070 Roo.TabPanel.prototype.createStrip = function(container){
26071 var strip = document.createElement("div");
26072 strip.className = "x-tabs-wrap";
26073 container.appendChild(strip);
26077 Roo.TabPanel.prototype.createStripList = function(strip){
26078 // div wrapper for retard IE
26079 // returns the "tr" element.
26080 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26081 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26082 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26083 return strip.firstChild.firstChild.firstChild.firstChild;
26086 Roo.TabPanel.prototype.createBody = function(container){
26087 var body = document.createElement("div");
26088 Roo.id(body, "tab-body");
26089 Roo.fly(body).addClass("x-tabs-body");
26090 container.appendChild(body);
26094 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26095 var body = Roo.getDom(id);
26097 body = document.createElement("div");
26100 Roo.fly(body).addClass("x-tabs-item-body");
26101 bodyEl.insertBefore(body, bodyEl.firstChild);
26105 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26106 var td = document.createElement("td");
26107 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26108 //stripEl.appendChild(td);
26110 td.className = "x-tabs-closable";
26111 if(!this.closeTpl){
26112 this.closeTpl = new Roo.Template(
26113 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26114 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26115 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26118 var el = this.closeTpl.overwrite(td, {"text": text});
26119 var close = el.getElementsByTagName("div")[0];
26120 var inner = el.getElementsByTagName("em")[0];
26121 return {"el": el, "close": close, "inner": inner};
26124 this.tabTpl = new Roo.Template(
26125 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26126 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26129 var el = this.tabTpl.overwrite(td, {"text": text});
26130 var inner = el.getElementsByTagName("em")[0];
26131 return {"el": el, "inner": inner};
26135 * Ext JS Library 1.1.1
26136 * Copyright(c) 2006-2007, Ext JS, LLC.
26138 * Originally Released Under LGPL - original licence link has changed is not relivant.
26141 * <script type="text/javascript">
26145 * @class Roo.Button
26146 * @extends Roo.util.Observable
26147 * Simple Button class
26148 * @cfg {String} text The button text
26149 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26150 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26151 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26152 * @cfg {Object} scope The scope of the handler
26153 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26154 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26155 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26156 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26157 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26158 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26159 applies if enableToggle = true)
26160 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26161 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26162 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26164 * Create a new button
26165 * @param {Object} config The config object
26167 Roo.Button = function(renderTo, config)
26171 renderTo = config.renderTo || false;
26174 Roo.apply(this, config);
26178 * Fires when this button is clicked
26179 * @param {Button} this
26180 * @param {EventObject} e The click event
26185 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26186 * @param {Button} this
26187 * @param {Boolean} pressed
26192 * Fires when the mouse hovers over the button
26193 * @param {Button} this
26194 * @param {Event} e The event object
26196 'mouseover' : true,
26199 * Fires when the mouse exits the button
26200 * @param {Button} this
26201 * @param {Event} e The event object
26206 * Fires when the button is rendered
26207 * @param {Button} this
26212 this.menu = Roo.menu.MenuMgr.get(this.menu);
26214 // register listeners first!! - so render can be captured..
26215 Roo.util.Observable.call(this);
26217 this.render(renderTo);
26223 Roo.extend(Roo.Button, Roo.util.Observable, {
26229 * Read-only. True if this button is hidden
26234 * Read-only. True if this button is disabled
26239 * Read-only. True if this button is pressed (only if enableToggle = true)
26245 * @cfg {Number} tabIndex
26246 * The DOM tabIndex for this button (defaults to undefined)
26248 tabIndex : undefined,
26251 * @cfg {Boolean} enableToggle
26252 * True to enable pressed/not pressed toggling (defaults to false)
26254 enableToggle: false,
26256 * @cfg {Mixed} menu
26257 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26261 * @cfg {String} menuAlign
26262 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26264 menuAlign : "tl-bl?",
26267 * @cfg {String} iconCls
26268 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26270 iconCls : undefined,
26272 * @cfg {String} type
26273 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26278 menuClassTarget: 'tr',
26281 * @cfg {String} clickEvent
26282 * The type of event to map to the button's event handler (defaults to 'click')
26284 clickEvent : 'click',
26287 * @cfg {Boolean} handleMouseEvents
26288 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26290 handleMouseEvents : true,
26293 * @cfg {String} tooltipType
26294 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26296 tooltipType : 'qtip',
26299 * @cfg {String} cls
26300 * A CSS class to apply to the button's main element.
26304 * @cfg {Roo.Template} template (Optional)
26305 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26306 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26307 * require code modifications if required elements (e.g. a button) aren't present.
26311 render : function(renderTo){
26313 if(this.hideParent){
26314 this.parentEl = Roo.get(renderTo);
26316 if(!this.dhconfig){
26317 if(!this.template){
26318 if(!Roo.Button.buttonTemplate){
26319 // hideous table template
26320 Roo.Button.buttonTemplate = new Roo.Template(
26321 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26322 '<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>',
26323 "</tr></tbody></table>");
26325 this.template = Roo.Button.buttonTemplate;
26327 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26328 var btnEl = btn.child("button:first");
26329 btnEl.on('focus', this.onFocus, this);
26330 btnEl.on('blur', this.onBlur, this);
26332 btn.addClass(this.cls);
26335 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26338 btnEl.addClass(this.iconCls);
26340 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26343 if(this.tabIndex !== undefined){
26344 btnEl.dom.tabIndex = this.tabIndex;
26347 if(typeof this.tooltip == 'object'){
26348 Roo.QuickTips.tips(Roo.apply({
26352 btnEl.dom[this.tooltipType] = this.tooltip;
26356 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26360 this.el.dom.id = this.el.id = this.id;
26363 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26364 this.menu.on("show", this.onMenuShow, this);
26365 this.menu.on("hide", this.onMenuHide, this);
26367 btn.addClass("x-btn");
26368 if(Roo.isIE && !Roo.isIE7){
26369 this.autoWidth.defer(1, this);
26373 if(this.handleMouseEvents){
26374 btn.on("mouseover", this.onMouseOver, this);
26375 btn.on("mouseout", this.onMouseOut, this);
26376 btn.on("mousedown", this.onMouseDown, this);
26378 btn.on(this.clickEvent, this.onClick, this);
26379 //btn.on("mouseup", this.onMouseUp, this);
26386 Roo.ButtonToggleMgr.register(this);
26388 this.el.addClass("x-btn-pressed");
26391 var repeater = new Roo.util.ClickRepeater(btn,
26392 typeof this.repeat == "object" ? this.repeat : {}
26394 repeater.on("click", this.onClick, this);
26397 this.fireEvent('render', this);
26401 * Returns the button's underlying element
26402 * @return {Roo.Element} The element
26404 getEl : function(){
26409 * Destroys this Button and removes any listeners.
26411 destroy : function(){
26412 Roo.ButtonToggleMgr.unregister(this);
26413 this.el.removeAllListeners();
26414 this.purgeListeners();
26419 autoWidth : function(){
26421 this.el.setWidth("auto");
26422 if(Roo.isIE7 && Roo.isStrict){
26423 var ib = this.el.child('button');
26424 if(ib && ib.getWidth() > 20){
26426 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26431 this.el.beginMeasure();
26433 if(this.el.getWidth() < this.minWidth){
26434 this.el.setWidth(this.minWidth);
26437 this.el.endMeasure();
26444 * Assigns this button's click handler
26445 * @param {Function} handler The function to call when the button is clicked
26446 * @param {Object} scope (optional) Scope for the function passed in
26448 setHandler : function(handler, scope){
26449 this.handler = handler;
26450 this.scope = scope;
26454 * Sets this button's text
26455 * @param {String} text The button text
26457 setText : function(text){
26460 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26466 * Gets the text for this button
26467 * @return {String} The button text
26469 getText : function(){
26477 this.hidden = false;
26479 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26487 this.hidden = true;
26489 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26494 * Convenience function for boolean show/hide
26495 * @param {Boolean} visible True to show, false to hide
26497 setVisible: function(visible){
26506 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26507 * @param {Boolean} state (optional) Force a particular state
26509 toggle : function(state){
26510 state = state === undefined ? !this.pressed : state;
26511 if(state != this.pressed){
26513 this.el.addClass("x-btn-pressed");
26514 this.pressed = true;
26515 this.fireEvent("toggle", this, true);
26517 this.el.removeClass("x-btn-pressed");
26518 this.pressed = false;
26519 this.fireEvent("toggle", this, false);
26521 if(this.toggleHandler){
26522 this.toggleHandler.call(this.scope || this, this, state);
26530 focus : function(){
26531 this.el.child('button:first').focus();
26535 * Disable this button
26537 disable : function(){
26539 this.el.addClass("x-btn-disabled");
26541 this.disabled = true;
26545 * Enable this button
26547 enable : function(){
26549 this.el.removeClass("x-btn-disabled");
26551 this.disabled = false;
26555 * Convenience function for boolean enable/disable
26556 * @param {Boolean} enabled True to enable, false to disable
26558 setDisabled : function(v){
26559 this[v !== true ? "enable" : "disable"]();
26563 onClick : function(e){
26565 e.preventDefault();
26570 if(!this.disabled){
26571 if(this.enableToggle){
26574 if(this.menu && !this.menu.isVisible()){
26575 this.menu.show(this.el, this.menuAlign);
26577 this.fireEvent("click", this, e);
26579 this.el.removeClass("x-btn-over");
26580 this.handler.call(this.scope || this, this, e);
26585 onMouseOver : function(e){
26586 if(!this.disabled){
26587 this.el.addClass("x-btn-over");
26588 this.fireEvent('mouseover', this, e);
26592 onMouseOut : function(e){
26593 if(!e.within(this.el, true)){
26594 this.el.removeClass("x-btn-over");
26595 this.fireEvent('mouseout', this, e);
26599 onFocus : function(e){
26600 if(!this.disabled){
26601 this.el.addClass("x-btn-focus");
26605 onBlur : function(e){
26606 this.el.removeClass("x-btn-focus");
26609 onMouseDown : function(e){
26610 if(!this.disabled && e.button == 0){
26611 this.el.addClass("x-btn-click");
26612 Roo.get(document).on('mouseup', this.onMouseUp, this);
26616 onMouseUp : function(e){
26618 this.el.removeClass("x-btn-click");
26619 Roo.get(document).un('mouseup', this.onMouseUp, this);
26623 onMenuShow : function(e){
26624 this.el.addClass("x-btn-menu-active");
26627 onMenuHide : function(e){
26628 this.el.removeClass("x-btn-menu-active");
26632 // Private utility class used by Button
26633 Roo.ButtonToggleMgr = function(){
26636 function toggleGroup(btn, state){
26638 var g = groups[btn.toggleGroup];
26639 for(var i = 0, l = g.length; i < l; i++){
26641 g[i].toggle(false);
26648 register : function(btn){
26649 if(!btn.toggleGroup){
26652 var g = groups[btn.toggleGroup];
26654 g = groups[btn.toggleGroup] = [];
26657 btn.on("toggle", toggleGroup);
26660 unregister : function(btn){
26661 if(!btn.toggleGroup){
26664 var g = groups[btn.toggleGroup];
26667 btn.un("toggle", toggleGroup);
26673 * Ext JS Library 1.1.1
26674 * Copyright(c) 2006-2007, Ext JS, LLC.
26676 * Originally Released Under LGPL - original licence link has changed is not relivant.
26679 * <script type="text/javascript">
26683 * @class Roo.SplitButton
26684 * @extends Roo.Button
26685 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26686 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26687 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26688 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26689 * @cfg {String} arrowTooltip The title attribute of the arrow
26691 * Create a new menu button
26692 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26693 * @param {Object} config The config object
26695 Roo.SplitButton = function(renderTo, config){
26696 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26698 * @event arrowclick
26699 * Fires when this button's arrow is clicked
26700 * @param {SplitButton} this
26701 * @param {EventObject} e The click event
26703 this.addEvents({"arrowclick":true});
26706 Roo.extend(Roo.SplitButton, Roo.Button, {
26707 render : function(renderTo){
26708 // this is one sweet looking template!
26709 var tpl = new Roo.Template(
26710 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26711 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26712 '<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>',
26713 "</tbody></table></td><td>",
26714 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26715 '<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>',
26716 "</tbody></table></td></tr></table>"
26718 var btn = tpl.append(renderTo, [this.text, this.type], true);
26719 var btnEl = btn.child("button");
26721 btn.addClass(this.cls);
26724 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26727 btnEl.addClass(this.iconCls);
26729 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26733 if(this.handleMouseEvents){
26734 btn.on("mouseover", this.onMouseOver, this);
26735 btn.on("mouseout", this.onMouseOut, this);
26736 btn.on("mousedown", this.onMouseDown, this);
26737 btn.on("mouseup", this.onMouseUp, this);
26739 btn.on(this.clickEvent, this.onClick, this);
26741 if(typeof this.tooltip == 'object'){
26742 Roo.QuickTips.tips(Roo.apply({
26746 btnEl.dom[this.tooltipType] = this.tooltip;
26749 if(this.arrowTooltip){
26750 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26759 this.el.addClass("x-btn-pressed");
26761 if(Roo.isIE && !Roo.isIE7){
26762 this.autoWidth.defer(1, this);
26767 this.menu.on("show", this.onMenuShow, this);
26768 this.menu.on("hide", this.onMenuHide, this);
26770 this.fireEvent('render', this);
26774 autoWidth : function(){
26776 var tbl = this.el.child("table:first");
26777 var tbl2 = this.el.child("table:last");
26778 this.el.setWidth("auto");
26779 tbl.setWidth("auto");
26780 if(Roo.isIE7 && Roo.isStrict){
26781 var ib = this.el.child('button:first');
26782 if(ib && ib.getWidth() > 20){
26784 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26789 this.el.beginMeasure();
26791 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26792 tbl.setWidth(this.minWidth-tbl2.getWidth());
26795 this.el.endMeasure();
26798 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26802 * Sets this button's click handler
26803 * @param {Function} handler The function to call when the button is clicked
26804 * @param {Object} scope (optional) Scope for the function passed above
26806 setHandler : function(handler, scope){
26807 this.handler = handler;
26808 this.scope = scope;
26812 * Sets this button's arrow click handler
26813 * @param {Function} handler The function to call when the arrow is clicked
26814 * @param {Object} scope (optional) Scope for the function passed above
26816 setArrowHandler : function(handler, scope){
26817 this.arrowHandler = handler;
26818 this.scope = scope;
26824 focus : function(){
26826 this.el.child("button:first").focus();
26831 onClick : function(e){
26832 e.preventDefault();
26833 if(!this.disabled){
26834 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26835 if(this.menu && !this.menu.isVisible()){
26836 this.menu.show(this.el, this.menuAlign);
26838 this.fireEvent("arrowclick", this, e);
26839 if(this.arrowHandler){
26840 this.arrowHandler.call(this.scope || this, this, e);
26843 this.fireEvent("click", this, e);
26845 this.handler.call(this.scope || this, this, e);
26851 onMouseDown : function(e){
26852 if(!this.disabled){
26853 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26857 onMouseUp : function(e){
26858 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26863 // backwards compat
26864 Roo.MenuButton = Roo.SplitButton;/*
26866 * Ext JS Library 1.1.1
26867 * Copyright(c) 2006-2007, Ext JS, LLC.
26869 * Originally Released Under LGPL - original licence link has changed is not relivant.
26872 * <script type="text/javascript">
26876 * @class Roo.Toolbar
26877 * Basic Toolbar class.
26879 * Creates a new Toolbar
26880 * @param {Object} container The config object
26882 Roo.Toolbar = function(container, buttons, config)
26884 /// old consturctor format still supported..
26885 if(container instanceof Array){ // omit the container for later rendering
26886 buttons = container;
26890 if (typeof(container) == 'object' && container.xtype) {
26891 config = container;
26892 container = config.container;
26893 buttons = config.buttons || []; // not really - use items!!
26896 if (config && config.items) {
26897 xitems = config.items;
26898 delete config.items;
26900 Roo.apply(this, config);
26901 this.buttons = buttons;
26904 this.render(container);
26906 this.xitems = xitems;
26907 Roo.each(xitems, function(b) {
26913 Roo.Toolbar.prototype = {
26915 * @cfg {Array} items
26916 * array of button configs or elements to add (will be converted to a MixedCollection)
26920 * @cfg {String/HTMLElement/Element} container
26921 * The id or element that will contain the toolbar
26924 render : function(ct){
26925 this.el = Roo.get(ct);
26927 this.el.addClass(this.cls);
26929 // using a table allows for vertical alignment
26930 // 100% width is needed by Safari...
26931 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26932 this.tr = this.el.child("tr", true);
26934 this.items = new Roo.util.MixedCollection(false, function(o){
26935 return o.id || ("item" + (++autoId));
26938 this.add.apply(this, this.buttons);
26939 delete this.buttons;
26944 * Adds element(s) to the toolbar -- this function takes a variable number of
26945 * arguments of mixed type and adds them to the toolbar.
26946 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26948 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26949 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26950 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26951 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26952 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26953 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26954 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26955 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26956 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26958 * @param {Mixed} arg2
26959 * @param {Mixed} etc.
26962 var a = arguments, l = a.length;
26963 for(var i = 0; i < l; i++){
26968 _add : function(el) {
26971 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26974 if (el.applyTo){ // some kind of form field
26975 return this.addField(el);
26977 if (el.render){ // some kind of Toolbar.Item
26978 return this.addItem(el);
26980 if (typeof el == "string"){ // string
26981 if(el == "separator" || el == "-"){
26982 return this.addSeparator();
26985 return this.addSpacer();
26988 return this.addFill();
26990 return this.addText(el);
26993 if(el.tagName){ // element
26994 return this.addElement(el);
26996 if(typeof el == "object"){ // must be button config?
26997 return this.addButton(el);
26999 // and now what?!?!
27005 * Add an Xtype element
27006 * @param {Object} xtype Xtype Object
27007 * @return {Object} created Object
27009 addxtype : function(e){
27010 return this.add(e);
27014 * Returns the Element for this toolbar.
27015 * @return {Roo.Element}
27017 getEl : function(){
27023 * @return {Roo.Toolbar.Item} The separator item
27025 addSeparator : function(){
27026 return this.addItem(new Roo.Toolbar.Separator());
27030 * Adds a spacer element
27031 * @return {Roo.Toolbar.Spacer} The spacer item
27033 addSpacer : function(){
27034 return this.addItem(new Roo.Toolbar.Spacer());
27038 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27039 * @return {Roo.Toolbar.Fill} The fill item
27041 addFill : function(){
27042 return this.addItem(new Roo.Toolbar.Fill());
27046 * Adds any standard HTML element to the toolbar
27047 * @param {String/HTMLElement/Element} el The element or id of the element to add
27048 * @return {Roo.Toolbar.Item} The element's item
27050 addElement : function(el){
27051 return this.addItem(new Roo.Toolbar.Item(el));
27054 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27055 * @type Roo.util.MixedCollection
27060 * Adds any Toolbar.Item or subclass
27061 * @param {Roo.Toolbar.Item} item
27062 * @return {Roo.Toolbar.Item} The item
27064 addItem : function(item){
27065 var td = this.nextBlock();
27067 this.items.add(item);
27072 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27073 * @param {Object/Array} config A button config or array of configs
27074 * @return {Roo.Toolbar.Button/Array}
27076 addButton : function(config){
27077 if(config instanceof Array){
27079 for(var i = 0, len = config.length; i < len; i++) {
27080 buttons.push(this.addButton(config[i]));
27085 if(!(config instanceof Roo.Toolbar.Button)){
27087 new Roo.Toolbar.SplitButton(config) :
27088 new Roo.Toolbar.Button(config);
27090 var td = this.nextBlock();
27097 * Adds text to the toolbar
27098 * @param {String} text The text to add
27099 * @return {Roo.Toolbar.Item} The element's item
27101 addText : function(text){
27102 return this.addItem(new Roo.Toolbar.TextItem(text));
27106 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27107 * @param {Number} index The index where the item is to be inserted
27108 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27109 * @return {Roo.Toolbar.Button/Item}
27111 insertButton : function(index, item){
27112 if(item instanceof Array){
27114 for(var i = 0, len = item.length; i < len; i++) {
27115 buttons.push(this.insertButton(index + i, item[i]));
27119 if (!(item instanceof Roo.Toolbar.Button)){
27120 item = new Roo.Toolbar.Button(item);
27122 var td = document.createElement("td");
27123 this.tr.insertBefore(td, this.tr.childNodes[index]);
27125 this.items.insert(index, item);
27130 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27131 * @param {Object} config
27132 * @return {Roo.Toolbar.Item} The element's item
27134 addDom : function(config, returnEl){
27135 var td = this.nextBlock();
27136 Roo.DomHelper.overwrite(td, config);
27137 var ti = new Roo.Toolbar.Item(td.firstChild);
27139 this.items.add(ti);
27144 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27145 * @type Roo.util.MixedCollection
27150 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27151 * Note: the field should not have been rendered yet. For a field that has already been
27152 * rendered, use {@link #addElement}.
27153 * @param {Roo.form.Field} field
27154 * @return {Roo.ToolbarItem}
27158 addField : function(field) {
27159 if (!this.fields) {
27161 this.fields = new Roo.util.MixedCollection(false, function(o){
27162 return o.id || ("item" + (++autoId));
27167 var td = this.nextBlock();
27169 var ti = new Roo.Toolbar.Item(td.firstChild);
27171 this.items.add(ti);
27172 this.fields.add(field);
27183 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27184 this.el.child('div').hide();
27192 this.el.child('div').show();
27196 nextBlock : function(){
27197 var td = document.createElement("td");
27198 this.tr.appendChild(td);
27203 destroy : function(){
27204 if(this.items){ // rendered?
27205 Roo.destroy.apply(Roo, this.items.items);
27207 if(this.fields){ // rendered?
27208 Roo.destroy.apply(Roo, this.fields.items);
27210 Roo.Element.uncache(this.el, this.tr);
27215 * @class Roo.Toolbar.Item
27216 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27218 * Creates a new Item
27219 * @param {HTMLElement} el
27221 Roo.Toolbar.Item = function(el){
27222 this.el = Roo.getDom(el);
27223 this.id = Roo.id(this.el);
27224 this.hidden = false;
27227 Roo.Toolbar.Item.prototype = {
27230 * Get this item's HTML Element
27231 * @return {HTMLElement}
27233 getEl : function(){
27238 render : function(td){
27240 td.appendChild(this.el);
27244 * Removes and destroys this item.
27246 destroy : function(){
27247 this.td.parentNode.removeChild(this.td);
27254 this.hidden = false;
27255 this.td.style.display = "";
27262 this.hidden = true;
27263 this.td.style.display = "none";
27267 * Convenience function for boolean show/hide.
27268 * @param {Boolean} visible true to show/false to hide
27270 setVisible: function(visible){
27279 * Try to focus this item.
27281 focus : function(){
27282 Roo.fly(this.el).focus();
27286 * Disables this item.
27288 disable : function(){
27289 Roo.fly(this.td).addClass("x-item-disabled");
27290 this.disabled = true;
27291 this.el.disabled = true;
27295 * Enables this item.
27297 enable : function(){
27298 Roo.fly(this.td).removeClass("x-item-disabled");
27299 this.disabled = false;
27300 this.el.disabled = false;
27306 * @class Roo.Toolbar.Separator
27307 * @extends Roo.Toolbar.Item
27308 * A simple toolbar separator class
27310 * Creates a new Separator
27312 Roo.Toolbar.Separator = function(){
27313 var s = document.createElement("span");
27314 s.className = "ytb-sep";
27315 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27317 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27318 enable:Roo.emptyFn,
27319 disable:Roo.emptyFn,
27324 * @class Roo.Toolbar.Spacer
27325 * @extends Roo.Toolbar.Item
27326 * A simple element that adds extra horizontal space to a toolbar.
27328 * Creates a new Spacer
27330 Roo.Toolbar.Spacer = function(){
27331 var s = document.createElement("div");
27332 s.className = "ytb-spacer";
27333 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27335 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27336 enable:Roo.emptyFn,
27337 disable:Roo.emptyFn,
27342 * @class Roo.Toolbar.Fill
27343 * @extends Roo.Toolbar.Spacer
27344 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27346 * Creates a new Spacer
27348 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27350 render : function(td){
27351 td.style.width = '100%';
27352 Roo.Toolbar.Fill.superclass.render.call(this, td);
27357 * @class Roo.Toolbar.TextItem
27358 * @extends Roo.Toolbar.Item
27359 * A simple class that renders text directly into a toolbar.
27361 * Creates a new TextItem
27362 * @param {String} text
27364 Roo.Toolbar.TextItem = function(text){
27365 if (typeof(text) == 'object') {
27368 var s = document.createElement("span");
27369 s.className = "ytb-text";
27370 s.innerHTML = text;
27371 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27373 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27374 enable:Roo.emptyFn,
27375 disable:Roo.emptyFn,
27380 * @class Roo.Toolbar.Button
27381 * @extends Roo.Button
27382 * A button that renders into a toolbar.
27384 * Creates a new Button
27385 * @param {Object} config A standard {@link Roo.Button} config object
27387 Roo.Toolbar.Button = function(config){
27388 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27390 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27391 render : function(td){
27393 Roo.Toolbar.Button.superclass.render.call(this, td);
27397 * Removes and destroys this button
27399 destroy : function(){
27400 Roo.Toolbar.Button.superclass.destroy.call(this);
27401 this.td.parentNode.removeChild(this.td);
27405 * Shows this button
27408 this.hidden = false;
27409 this.td.style.display = "";
27413 * Hides this button
27416 this.hidden = true;
27417 this.td.style.display = "none";
27421 * Disables this item
27423 disable : function(){
27424 Roo.fly(this.td).addClass("x-item-disabled");
27425 this.disabled = true;
27429 * Enables this item
27431 enable : function(){
27432 Roo.fly(this.td).removeClass("x-item-disabled");
27433 this.disabled = false;
27436 // backwards compat
27437 Roo.ToolbarButton = Roo.Toolbar.Button;
27440 * @class Roo.Toolbar.SplitButton
27441 * @extends Roo.SplitButton
27442 * A menu button that renders into a toolbar.
27444 * Creates a new SplitButton
27445 * @param {Object} config A standard {@link Roo.SplitButton} config object
27447 Roo.Toolbar.SplitButton = function(config){
27448 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27450 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27451 render : function(td){
27453 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27457 * Removes and destroys this button
27459 destroy : function(){
27460 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27461 this.td.parentNode.removeChild(this.td);
27465 * Shows this button
27468 this.hidden = false;
27469 this.td.style.display = "";
27473 * Hides this button
27476 this.hidden = true;
27477 this.td.style.display = "none";
27481 // backwards compat
27482 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27484 * Ext JS Library 1.1.1
27485 * Copyright(c) 2006-2007, Ext JS, LLC.
27487 * Originally Released Under LGPL - original licence link has changed is not relivant.
27490 * <script type="text/javascript">
27494 * @class Roo.PagingToolbar
27495 * @extends Roo.Toolbar
27496 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27498 * Create a new PagingToolbar
27499 * @param {Object} config The config object
27501 Roo.PagingToolbar = function(el, ds, config)
27503 // old args format still supported... - xtype is prefered..
27504 if (typeof(el) == 'object' && el.xtype) {
27505 // created from xtype...
27507 ds = el.dataSource;
27508 el = config.container;
27511 if (config.items) {
27512 items = config.items;
27516 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27519 this.renderButtons(this.el);
27522 // supprot items array.
27524 Roo.each(items, function(e) {
27525 this.add(Roo.factory(e));
27530 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27532 * @cfg {Roo.data.Store} dataSource
27533 * The underlying data store providing the paged data
27536 * @cfg {String/HTMLElement/Element} container
27537 * container The id or element that will contain the toolbar
27540 * @cfg {Boolean} displayInfo
27541 * True to display the displayMsg (defaults to false)
27544 * @cfg {Number} pageSize
27545 * The number of records to display per page (defaults to 20)
27549 * @cfg {String} displayMsg
27550 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27552 displayMsg : 'Displaying {0} - {1} of {2}',
27554 * @cfg {String} emptyMsg
27555 * The message to display when no records are found (defaults to "No data to display")
27557 emptyMsg : 'No data to display',
27559 * Customizable piece of the default paging text (defaults to "Page")
27562 beforePageText : "Page",
27564 * Customizable piece of the default paging text (defaults to "of %0")
27567 afterPageText : "of {0}",
27569 * Customizable piece of the default paging text (defaults to "First Page")
27572 firstText : "First Page",
27574 * Customizable piece of the default paging text (defaults to "Previous Page")
27577 prevText : "Previous Page",
27579 * Customizable piece of the default paging text (defaults to "Next Page")
27582 nextText : "Next Page",
27584 * Customizable piece of the default paging text (defaults to "Last Page")
27587 lastText : "Last Page",
27589 * Customizable piece of the default paging text (defaults to "Refresh")
27592 refreshText : "Refresh",
27595 renderButtons : function(el){
27596 Roo.PagingToolbar.superclass.render.call(this, el);
27597 this.first = this.addButton({
27598 tooltip: this.firstText,
27599 cls: "x-btn-icon x-grid-page-first",
27601 handler: this.onClick.createDelegate(this, ["first"])
27603 this.prev = this.addButton({
27604 tooltip: this.prevText,
27605 cls: "x-btn-icon x-grid-page-prev",
27607 handler: this.onClick.createDelegate(this, ["prev"])
27609 //this.addSeparator();
27610 this.add(this.beforePageText);
27611 this.field = Roo.get(this.addDom({
27616 cls: "x-grid-page-number"
27618 this.field.on("keydown", this.onPagingKeydown, this);
27619 this.field.on("focus", function(){this.dom.select();});
27620 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27621 this.field.setHeight(18);
27622 //this.addSeparator();
27623 this.next = this.addButton({
27624 tooltip: this.nextText,
27625 cls: "x-btn-icon x-grid-page-next",
27627 handler: this.onClick.createDelegate(this, ["next"])
27629 this.last = this.addButton({
27630 tooltip: this.lastText,
27631 cls: "x-btn-icon x-grid-page-last",
27633 handler: this.onClick.createDelegate(this, ["last"])
27635 //this.addSeparator();
27636 this.loading = this.addButton({
27637 tooltip: this.refreshText,
27638 cls: "x-btn-icon x-grid-loading",
27639 handler: this.onClick.createDelegate(this, ["refresh"])
27642 if(this.displayInfo){
27643 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27648 updateInfo : function(){
27649 if(this.displayEl){
27650 var count = this.ds.getCount();
27651 var msg = count == 0 ?
27655 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27657 this.displayEl.update(msg);
27662 onLoad : function(ds, r, o){
27663 this.cursor = o.params ? o.params.start : 0;
27664 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27666 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27667 this.field.dom.value = ap;
27668 this.first.setDisabled(ap == 1);
27669 this.prev.setDisabled(ap == 1);
27670 this.next.setDisabled(ap == ps);
27671 this.last.setDisabled(ap == ps);
27672 this.loading.enable();
27677 getPageData : function(){
27678 var total = this.ds.getTotalCount();
27681 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27682 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27687 onLoadError : function(){
27688 this.loading.enable();
27692 onPagingKeydown : function(e){
27693 var k = e.getKey();
27694 var d = this.getPageData();
27696 var v = this.field.dom.value, pageNum;
27697 if(!v || isNaN(pageNum = parseInt(v, 10))){
27698 this.field.dom.value = d.activePage;
27701 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27702 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27705 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))
27707 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27708 this.field.dom.value = pageNum;
27709 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27712 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27714 var v = this.field.dom.value, pageNum;
27715 var increment = (e.shiftKey) ? 10 : 1;
27716 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27718 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27719 this.field.dom.value = d.activePage;
27722 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27724 this.field.dom.value = parseInt(v, 10) + increment;
27725 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27726 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27733 beforeLoad : function(){
27735 this.loading.disable();
27740 onClick : function(which){
27744 ds.load({params:{start: 0, limit: this.pageSize}});
27747 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27750 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27753 var total = ds.getTotalCount();
27754 var extra = total % this.pageSize;
27755 var lastStart = extra ? (total - extra) : total-this.pageSize;
27756 ds.load({params:{start: lastStart, limit: this.pageSize}});
27759 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27765 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27766 * @param {Roo.data.Store} store The data store to unbind
27768 unbind : function(ds){
27769 ds.un("beforeload", this.beforeLoad, this);
27770 ds.un("load", this.onLoad, this);
27771 ds.un("loadexception", this.onLoadError, this);
27772 ds.un("remove", this.updateInfo, this);
27773 ds.un("add", this.updateInfo, this);
27774 this.ds = undefined;
27778 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27779 * @param {Roo.data.Store} store The data store to bind
27781 bind : function(ds){
27782 ds.on("beforeload", this.beforeLoad, this);
27783 ds.on("load", this.onLoad, this);
27784 ds.on("loadexception", this.onLoadError, this);
27785 ds.on("remove", this.updateInfo, this);
27786 ds.on("add", this.updateInfo, this);
27791 * Ext JS Library 1.1.1
27792 * Copyright(c) 2006-2007, Ext JS, LLC.
27794 * Originally Released Under LGPL - original licence link has changed is not relivant.
27797 * <script type="text/javascript">
27801 * @class Roo.Resizable
27802 * @extends Roo.util.Observable
27803 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27804 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27805 * 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
27806 * the element will be wrapped for you automatically.</p>
27807 * <p>Here is the list of valid resize handles:</p>
27810 ------ -------------------
27819 'hd' horizontal drag
27822 * <p>Here's an example showing the creation of a typical Resizable:</p>
27824 var resizer = new Roo.Resizable("element-id", {
27832 resizer.on("resize", myHandler);
27834 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27835 * resizer.east.setDisplayed(false);</p>
27836 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27837 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27838 * resize operation's new size (defaults to [0, 0])
27839 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27840 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27841 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27842 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27843 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27844 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27845 * @cfg {Number} width The width of the element in pixels (defaults to null)
27846 * @cfg {Number} height The height of the element in pixels (defaults to null)
27847 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27848 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27849 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27850 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27851 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27852 * in favor of the handles config option (defaults to false)
27853 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27854 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27855 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27856 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27857 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27858 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27859 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27860 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27861 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27862 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27863 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27865 * Create a new resizable component
27866 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27867 * @param {Object} config configuration options
27869 Roo.Resizable = function(el, config)
27871 this.el = Roo.get(el);
27873 if(config && config.wrap){
27874 config.resizeChild = this.el;
27875 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27876 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27877 this.el.setStyle("overflow", "hidden");
27878 this.el.setPositioning(config.resizeChild.getPositioning());
27879 config.resizeChild.clearPositioning();
27880 if(!config.width || !config.height){
27881 var csize = config.resizeChild.getSize();
27882 this.el.setSize(csize.width, csize.height);
27884 if(config.pinned && !config.adjustments){
27885 config.adjustments = "auto";
27889 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27890 this.proxy.unselectable();
27891 this.proxy.enableDisplayMode('block');
27893 Roo.apply(this, config);
27896 this.disableTrackOver = true;
27897 this.el.addClass("x-resizable-pinned");
27899 // if the element isn't positioned, make it relative
27900 var position = this.el.getStyle("position");
27901 if(position != "absolute" && position != "fixed"){
27902 this.el.setStyle("position", "relative");
27904 if(!this.handles){ // no handles passed, must be legacy style
27905 this.handles = 's,e,se';
27906 if(this.multiDirectional){
27907 this.handles += ',n,w';
27910 if(this.handles == "all"){
27911 this.handles = "n s e w ne nw se sw";
27913 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27914 var ps = Roo.Resizable.positions;
27915 for(var i = 0, len = hs.length; i < len; i++){
27916 if(hs[i] && ps[hs[i]]){
27917 var pos = ps[hs[i]];
27918 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27922 this.corner = this.southeast;
27924 // updateBox = the box can move..
27925 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27926 this.updateBox = true;
27929 this.activeHandle = null;
27931 if(this.resizeChild){
27932 if(typeof this.resizeChild == "boolean"){
27933 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27935 this.resizeChild = Roo.get(this.resizeChild, true);
27939 if(this.adjustments == "auto"){
27940 var rc = this.resizeChild;
27941 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27942 if(rc && (hw || hn)){
27943 rc.position("relative");
27944 rc.setLeft(hw ? hw.el.getWidth() : 0);
27945 rc.setTop(hn ? hn.el.getHeight() : 0);
27947 this.adjustments = [
27948 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27949 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27953 if(this.draggable){
27954 this.dd = this.dynamic ?
27955 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27956 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27962 * @event beforeresize
27963 * Fired before resize is allowed. Set enabled to false to cancel resize.
27964 * @param {Roo.Resizable} this
27965 * @param {Roo.EventObject} e The mousedown event
27967 "beforeresize" : true,
27970 * Fired after a resize.
27971 * @param {Roo.Resizable} this
27972 * @param {Number} width The new width
27973 * @param {Number} height The new height
27974 * @param {Roo.EventObject} e The mouseup event
27979 if(this.width !== null && this.height !== null){
27980 this.resizeTo(this.width, this.height);
27982 this.updateChildSize();
27985 this.el.dom.style.zoom = 1;
27987 Roo.Resizable.superclass.constructor.call(this);
27990 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27991 resizeChild : false,
27992 adjustments : [0, 0],
28002 multiDirectional : false,
28003 disableTrackOver : false,
28004 easing : 'easeOutStrong',
28005 widthIncrement : 0,
28006 heightIncrement : 0,
28010 preserveRatio : false,
28011 transparent: false,
28017 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28019 constrainTo: undefined,
28021 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28023 resizeRegion: undefined,
28027 * Perform a manual resize
28028 * @param {Number} width
28029 * @param {Number} height
28031 resizeTo : function(width, height){
28032 this.el.setSize(width, height);
28033 this.updateChildSize();
28034 this.fireEvent("resize", this, width, height, null);
28038 startSizing : function(e, handle){
28039 this.fireEvent("beforeresize", this, e);
28040 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28043 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28044 this.overlay.unselectable();
28045 this.overlay.enableDisplayMode("block");
28046 this.overlay.on("mousemove", this.onMouseMove, this);
28047 this.overlay.on("mouseup", this.onMouseUp, this);
28049 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28051 this.resizing = true;
28052 this.startBox = this.el.getBox();
28053 this.startPoint = e.getXY();
28054 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28055 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28057 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28058 this.overlay.show();
28060 if(this.constrainTo) {
28061 var ct = Roo.get(this.constrainTo);
28062 this.resizeRegion = ct.getRegion().adjust(
28063 ct.getFrameWidth('t'),
28064 ct.getFrameWidth('l'),
28065 -ct.getFrameWidth('b'),
28066 -ct.getFrameWidth('r')
28070 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28072 this.proxy.setBox(this.startBox);
28074 this.proxy.setStyle('visibility', 'visible');
28080 onMouseDown : function(handle, e){
28083 this.activeHandle = handle;
28084 this.startSizing(e, handle);
28089 onMouseUp : function(e){
28090 var size = this.resizeElement();
28091 this.resizing = false;
28093 this.overlay.hide();
28095 this.fireEvent("resize", this, size.width, size.height, e);
28099 updateChildSize : function(){
28100 if(this.resizeChild){
28102 var child = this.resizeChild;
28103 var adj = this.adjustments;
28104 if(el.dom.offsetWidth){
28105 var b = el.getSize(true);
28106 child.setSize(b.width+adj[0], b.height+adj[1]);
28108 // Second call here for IE
28109 // The first call enables instant resizing and
28110 // the second call corrects scroll bars if they
28113 setTimeout(function(){
28114 if(el.dom.offsetWidth){
28115 var b = el.getSize(true);
28116 child.setSize(b.width+adj[0], b.height+adj[1]);
28124 snap : function(value, inc, min){
28125 if(!inc || !value) return value;
28126 var newValue = value;
28127 var m = value % inc;
28130 newValue = value + (inc-m);
28132 newValue = value - m;
28135 return Math.max(min, newValue);
28139 resizeElement : function(){
28140 var box = this.proxy.getBox();
28141 if(this.updateBox){
28142 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28144 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28146 this.updateChildSize();
28154 constrain : function(v, diff, m, mx){
28157 }else if(v - diff > mx){
28164 onMouseMove : function(e){
28166 try{// try catch so if something goes wrong the user doesn't get hung
28168 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28172 //var curXY = this.startPoint;
28173 var curSize = this.curSize || this.startBox;
28174 var x = this.startBox.x, y = this.startBox.y;
28175 var ox = x, oy = y;
28176 var w = curSize.width, h = curSize.height;
28177 var ow = w, oh = h;
28178 var mw = this.minWidth, mh = this.minHeight;
28179 var mxw = this.maxWidth, mxh = this.maxHeight;
28180 var wi = this.widthIncrement;
28181 var hi = this.heightIncrement;
28183 var eventXY = e.getXY();
28184 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28185 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28187 var pos = this.activeHandle.position;
28192 w = Math.min(Math.max(mw, w), mxw);
28197 h = Math.min(Math.max(mh, h), mxh);
28202 w = Math.min(Math.max(mw, w), mxw);
28203 h = Math.min(Math.max(mh, h), mxh);
28206 diffY = this.constrain(h, diffY, mh, mxh);
28213 var adiffX = Math.abs(diffX);
28214 var sub = (adiffX % wi); // how much
28215 if (sub > (wi/2)) { // far enough to snap
28216 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28218 // remove difference..
28219 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28223 x = Math.max(this.minX, x);
28226 diffX = this.constrain(w, diffX, mw, mxw);
28232 w = Math.min(Math.max(mw, w), mxw);
28233 diffY = this.constrain(h, diffY, mh, mxh);
28238 diffX = this.constrain(w, diffX, mw, mxw);
28239 diffY = this.constrain(h, diffY, mh, mxh);
28246 diffX = this.constrain(w, diffX, mw, mxw);
28248 h = Math.min(Math.max(mh, h), mxh);
28254 var sw = this.snap(w, wi, mw);
28255 var sh = this.snap(h, hi, mh);
28256 if(sw != w || sh != h){
28279 if(this.preserveRatio){
28284 h = Math.min(Math.max(mh, h), mxh);
28289 w = Math.min(Math.max(mw, w), mxw);
28294 w = Math.min(Math.max(mw, w), mxw);
28300 w = Math.min(Math.max(mw, w), mxw);
28306 h = Math.min(Math.max(mh, h), mxh);
28314 h = Math.min(Math.max(mh, h), mxh);
28324 h = Math.min(Math.max(mh, h), mxh);
28332 if (pos == 'hdrag') {
28335 this.proxy.setBounds(x, y, w, h);
28337 this.resizeElement();
28344 handleOver : function(){
28346 this.el.addClass("x-resizable-over");
28351 handleOut : function(){
28352 if(!this.resizing){
28353 this.el.removeClass("x-resizable-over");
28358 * Returns the element this component is bound to.
28359 * @return {Roo.Element}
28361 getEl : function(){
28366 * Returns the resizeChild element (or null).
28367 * @return {Roo.Element}
28369 getResizeChild : function(){
28370 return this.resizeChild;
28374 * Destroys this resizable. If the element was wrapped and
28375 * removeEl is not true then the element remains.
28376 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28378 destroy : function(removeEl){
28379 this.proxy.remove();
28381 this.overlay.removeAllListeners();
28382 this.overlay.remove();
28384 var ps = Roo.Resizable.positions;
28386 if(typeof ps[k] != "function" && this[ps[k]]){
28387 var h = this[ps[k]];
28388 h.el.removeAllListeners();
28393 this.el.update("");
28400 // hash to map config positions to true positions
28401 Roo.Resizable.positions = {
28402 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28407 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28409 // only initialize the template if resizable is used
28410 var tpl = Roo.DomHelper.createTemplate(
28411 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28414 Roo.Resizable.Handle.prototype.tpl = tpl;
28416 this.position = pos;
28418 // show north drag fro topdra
28419 var handlepos = pos == 'hdrag' ? 'north' : pos;
28421 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28422 if (pos == 'hdrag') {
28423 this.el.setStyle('cursor', 'pointer');
28425 this.el.unselectable();
28427 this.el.setOpacity(0);
28429 this.el.on("mousedown", this.onMouseDown, this);
28430 if(!disableTrackOver){
28431 this.el.on("mouseover", this.onMouseOver, this);
28432 this.el.on("mouseout", this.onMouseOut, this);
28437 Roo.Resizable.Handle.prototype = {
28438 afterResize : function(rz){
28442 onMouseDown : function(e){
28443 this.rz.onMouseDown(this, e);
28446 onMouseOver : function(e){
28447 this.rz.handleOver(this, e);
28450 onMouseOut : function(e){
28451 this.rz.handleOut(this, e);
28455 * Ext JS Library 1.1.1
28456 * Copyright(c) 2006-2007, Ext JS, LLC.
28458 * Originally Released Under LGPL - original licence link has changed is not relivant.
28461 * <script type="text/javascript">
28465 * @class Roo.Editor
28466 * @extends Roo.Component
28467 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28469 * Create a new Editor
28470 * @param {Roo.form.Field} field The Field object (or descendant)
28471 * @param {Object} config The config object
28473 Roo.Editor = function(field, config){
28474 Roo.Editor.superclass.constructor.call(this, config);
28475 this.field = field;
28478 * @event beforestartedit
28479 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28480 * false from the handler of this event.
28481 * @param {Editor} this
28482 * @param {Roo.Element} boundEl The underlying element bound to this editor
28483 * @param {Mixed} value The field value being set
28485 "beforestartedit" : true,
28488 * Fires when this editor is displayed
28489 * @param {Roo.Element} boundEl The underlying element bound to this editor
28490 * @param {Mixed} value The starting field value
28492 "startedit" : true,
28494 * @event beforecomplete
28495 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28496 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28497 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28498 * event will not fire since no edit actually occurred.
28499 * @param {Editor} this
28500 * @param {Mixed} value The current field value
28501 * @param {Mixed} startValue The original field value
28503 "beforecomplete" : true,
28506 * Fires after editing is complete and any changed value has been written to the underlying field.
28507 * @param {Editor} this
28508 * @param {Mixed} value The current field value
28509 * @param {Mixed} startValue The original field value
28513 * @event specialkey
28514 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28515 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28516 * @param {Roo.form.Field} this
28517 * @param {Roo.EventObject} e The event object
28519 "specialkey" : true
28523 Roo.extend(Roo.Editor, Roo.Component, {
28525 * @cfg {Boolean/String} autosize
28526 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28527 * or "height" to adopt the height only (defaults to false)
28530 * @cfg {Boolean} revertInvalid
28531 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28532 * validation fails (defaults to true)
28535 * @cfg {Boolean} ignoreNoChange
28536 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28537 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28538 * will never be ignored.
28541 * @cfg {Boolean} hideEl
28542 * False to keep the bound element visible while the editor is displayed (defaults to true)
28545 * @cfg {Mixed} value
28546 * The data value of the underlying field (defaults to "")
28550 * @cfg {String} alignment
28551 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28555 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28556 * for bottom-right shadow (defaults to "frame")
28560 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28564 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28566 completeOnEnter : false,
28568 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28570 cancelOnEsc : false,
28572 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28577 onRender : function(ct, position){
28578 this.el = new Roo.Layer({
28579 shadow: this.shadow,
28585 constrain: this.constrain
28587 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28588 if(this.field.msgTarget != 'title'){
28589 this.field.msgTarget = 'qtip';
28591 this.field.render(this.el);
28593 this.field.el.dom.setAttribute('autocomplete', 'off');
28595 this.field.on("specialkey", this.onSpecialKey, this);
28596 if(this.swallowKeys){
28597 this.field.el.swallowEvent(['keydown','keypress']);
28600 this.field.on("blur", this.onBlur, this);
28601 if(this.field.grow){
28602 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28606 onSpecialKey : function(field, e)
28608 //Roo.log('editor onSpecialKey');
28609 if(this.completeOnEnter && e.getKey() == e.ENTER){
28611 this.completeEdit();
28614 // do not fire special key otherwise it might hide close the editor...
28615 if(e.getKey() == e.ENTER){
28618 if(this.cancelOnEsc && e.getKey() == e.ESC){
28622 this.fireEvent('specialkey', field, e);
28627 * Starts the editing process and shows the editor.
28628 * @param {String/HTMLElement/Element} el The element to edit
28629 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28630 * to the innerHTML of el.
28632 startEdit : function(el, value){
28634 this.completeEdit();
28636 this.boundEl = Roo.get(el);
28637 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28638 if(!this.rendered){
28639 this.render(this.parentEl || document.body);
28641 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28644 this.startValue = v;
28645 this.field.setValue(v);
28647 var sz = this.boundEl.getSize();
28648 switch(this.autoSize){
28650 this.setSize(sz.width, "");
28653 this.setSize("", sz.height);
28656 this.setSize(sz.width, sz.height);
28659 this.el.alignTo(this.boundEl, this.alignment);
28660 this.editing = true;
28662 Roo.QuickTips.disable();
28668 * Sets the height and width of this editor.
28669 * @param {Number} width The new width
28670 * @param {Number} height The new height
28672 setSize : function(w, h){
28673 this.field.setSize(w, h);
28680 * Realigns the editor to the bound field based on the current alignment config value.
28682 realign : function(){
28683 this.el.alignTo(this.boundEl, this.alignment);
28687 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28688 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28690 completeEdit : function(remainVisible){
28694 var v = this.getValue();
28695 if(this.revertInvalid !== false && !this.field.isValid()){
28696 v = this.startValue;
28697 this.cancelEdit(true);
28699 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28700 this.editing = false;
28704 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28705 this.editing = false;
28706 if(this.updateEl && this.boundEl){
28707 this.boundEl.update(v);
28709 if(remainVisible !== true){
28712 this.fireEvent("complete", this, v, this.startValue);
28717 onShow : function(){
28719 if(this.hideEl !== false){
28720 this.boundEl.hide();
28723 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28724 this.fixIEFocus = true;
28725 this.deferredFocus.defer(50, this);
28727 this.field.focus();
28729 this.fireEvent("startedit", this.boundEl, this.startValue);
28732 deferredFocus : function(){
28734 this.field.focus();
28739 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28740 * reverted to the original starting value.
28741 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28742 * cancel (defaults to false)
28744 cancelEdit : function(remainVisible){
28746 this.setValue(this.startValue);
28747 if(remainVisible !== true){
28754 onBlur : function(){
28755 if(this.allowBlur !== true && this.editing){
28756 this.completeEdit();
28761 onHide : function(){
28763 this.completeEdit();
28767 if(this.field.collapse){
28768 this.field.collapse();
28771 if(this.hideEl !== false){
28772 this.boundEl.show();
28775 Roo.QuickTips.enable();
28780 * Sets the data value of the editor
28781 * @param {Mixed} value Any valid value supported by the underlying field
28783 setValue : function(v){
28784 this.field.setValue(v);
28788 * Gets the data value of the editor
28789 * @return {Mixed} The data value
28791 getValue : function(){
28792 return this.field.getValue();
28796 * Ext JS Library 1.1.1
28797 * Copyright(c) 2006-2007, Ext JS, LLC.
28799 * Originally Released Under LGPL - original licence link has changed is not relivant.
28802 * <script type="text/javascript">
28806 * @class Roo.BasicDialog
28807 * @extends Roo.util.Observable
28808 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28810 var dlg = new Roo.BasicDialog("my-dlg", {
28819 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28820 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28821 dlg.addButton('Cancel', dlg.hide, dlg);
28824 <b>A Dialog should always be a direct child of the body element.</b>
28825 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28826 * @cfg {String} title Default text to display in the title bar (defaults to null)
28827 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28828 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28829 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28830 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28831 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28832 * (defaults to null with no animation)
28833 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28834 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28835 * property for valid values (defaults to 'all')
28836 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28837 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28838 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28839 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28840 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28841 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28842 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28843 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28844 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28845 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28846 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28847 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28848 * draggable = true (defaults to false)
28849 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28850 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28851 * shadow (defaults to false)
28852 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28853 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28854 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28855 * @cfg {Array} buttons Array of buttons
28856 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28858 * Create a new BasicDialog.
28859 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28860 * @param {Object} config Configuration options
28862 Roo.BasicDialog = function(el, config){
28863 this.el = Roo.get(el);
28864 var dh = Roo.DomHelper;
28865 if(!this.el && config && config.autoCreate){
28866 if(typeof config.autoCreate == "object"){
28867 if(!config.autoCreate.id){
28868 config.autoCreate.id = el;
28870 this.el = dh.append(document.body,
28871 config.autoCreate, true);
28873 this.el = dh.append(document.body,
28874 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28878 el.setDisplayed(true);
28879 el.hide = this.hideAction;
28881 el.addClass("x-dlg");
28883 Roo.apply(this, config);
28885 this.proxy = el.createProxy("x-dlg-proxy");
28886 this.proxy.hide = this.hideAction;
28887 this.proxy.setOpacity(.5);
28891 el.setWidth(config.width);
28894 el.setHeight(config.height);
28896 this.size = el.getSize();
28897 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28898 this.xy = [config.x,config.y];
28900 this.xy = el.getCenterXY(true);
28902 /** The header element @type Roo.Element */
28903 this.header = el.child("> .x-dlg-hd");
28904 /** The body element @type Roo.Element */
28905 this.body = el.child("> .x-dlg-bd");
28906 /** The footer element @type Roo.Element */
28907 this.footer = el.child("> .x-dlg-ft");
28910 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28913 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28916 this.header.unselectable();
28918 this.header.update(this.title);
28920 // this element allows the dialog to be focused for keyboard event
28921 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28922 this.focusEl.swallowEvent("click", true);
28924 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28926 // wrap the body and footer for special rendering
28927 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28929 this.bwrap.dom.appendChild(this.footer.dom);
28932 this.bg = this.el.createChild({
28933 tag: "div", cls:"x-dlg-bg",
28934 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28936 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28939 if(this.autoScroll !== false && !this.autoTabs){
28940 this.body.setStyle("overflow", "auto");
28943 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28945 if(this.closable !== false){
28946 this.el.addClass("x-dlg-closable");
28947 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28948 this.close.on("click", this.closeClick, this);
28949 this.close.addClassOnOver("x-dlg-close-over");
28951 if(this.collapsible !== false){
28952 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28953 this.collapseBtn.on("click", this.collapseClick, this);
28954 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28955 this.header.on("dblclick", this.collapseClick, this);
28957 if(this.resizable !== false){
28958 this.el.addClass("x-dlg-resizable");
28959 this.resizer = new Roo.Resizable(el, {
28960 minWidth: this.minWidth || 80,
28961 minHeight:this.minHeight || 80,
28962 handles: this.resizeHandles || "all",
28965 this.resizer.on("beforeresize", this.beforeResize, this);
28966 this.resizer.on("resize", this.onResize, this);
28968 if(this.draggable !== false){
28969 el.addClass("x-dlg-draggable");
28970 if (!this.proxyDrag) {
28971 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28974 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28976 dd.setHandleElId(this.header.id);
28977 dd.endDrag = this.endMove.createDelegate(this);
28978 dd.startDrag = this.startMove.createDelegate(this);
28979 dd.onDrag = this.onDrag.createDelegate(this);
28984 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28985 this.mask.enableDisplayMode("block");
28987 this.el.addClass("x-dlg-modal");
28990 this.shadow = new Roo.Shadow({
28991 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28992 offset : this.shadowOffset
28995 this.shadowOffset = 0;
28997 if(Roo.useShims && this.shim !== false){
28998 this.shim = this.el.createShim();
28999 this.shim.hide = this.hideAction;
29007 if (this.buttons) {
29008 var bts= this.buttons;
29010 Roo.each(bts, function(b) {
29019 * Fires when a key is pressed
29020 * @param {Roo.BasicDialog} this
29021 * @param {Roo.EventObject} e
29026 * Fires when this dialog is moved by the user.
29027 * @param {Roo.BasicDialog} this
29028 * @param {Number} x The new page X
29029 * @param {Number} y The new page Y
29034 * Fires when this dialog is resized by the user.
29035 * @param {Roo.BasicDialog} this
29036 * @param {Number} width The new width
29037 * @param {Number} height The new height
29041 * @event beforehide
29042 * Fires before this dialog is hidden.
29043 * @param {Roo.BasicDialog} this
29045 "beforehide" : true,
29048 * Fires when this dialog is hidden.
29049 * @param {Roo.BasicDialog} this
29053 * @event beforeshow
29054 * Fires before this dialog is shown.
29055 * @param {Roo.BasicDialog} this
29057 "beforeshow" : true,
29060 * Fires when this dialog is shown.
29061 * @param {Roo.BasicDialog} this
29065 el.on("keydown", this.onKeyDown, this);
29066 el.on("mousedown", this.toFront, this);
29067 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29069 Roo.DialogManager.register(this);
29070 Roo.BasicDialog.superclass.constructor.call(this);
29073 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29074 shadowOffset: Roo.isIE ? 6 : 5,
29077 minButtonWidth: 75,
29078 defaultButton: null,
29079 buttonAlign: "right",
29084 * Sets the dialog title text
29085 * @param {String} text The title text to display
29086 * @return {Roo.BasicDialog} this
29088 setTitle : function(text){
29089 this.header.update(text);
29094 closeClick : function(){
29099 collapseClick : function(){
29100 this[this.collapsed ? "expand" : "collapse"]();
29104 * Collapses the dialog to its minimized state (only the title bar is visible).
29105 * Equivalent to the user clicking the collapse dialog button.
29107 collapse : function(){
29108 if(!this.collapsed){
29109 this.collapsed = true;
29110 this.el.addClass("x-dlg-collapsed");
29111 this.restoreHeight = this.el.getHeight();
29112 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29117 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29118 * clicking the expand dialog button.
29120 expand : function(){
29121 if(this.collapsed){
29122 this.collapsed = false;
29123 this.el.removeClass("x-dlg-collapsed");
29124 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29129 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29130 * @return {Roo.TabPanel} The tabs component
29132 initTabs : function(){
29133 var tabs = this.getTabs();
29134 while(tabs.getTab(0)){
29137 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29139 tabs.addTab(Roo.id(dom), dom.title);
29147 beforeResize : function(){
29148 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29152 onResize : function(){
29153 this.refreshSize();
29154 this.syncBodyHeight();
29155 this.adjustAssets();
29157 this.fireEvent("resize", this, this.size.width, this.size.height);
29161 onKeyDown : function(e){
29162 if(this.isVisible()){
29163 this.fireEvent("keydown", this, e);
29168 * Resizes the dialog.
29169 * @param {Number} width
29170 * @param {Number} height
29171 * @return {Roo.BasicDialog} this
29173 resizeTo : function(width, height){
29174 this.el.setSize(width, height);
29175 this.size = {width: width, height: height};
29176 this.syncBodyHeight();
29177 if(this.fixedcenter){
29180 if(this.isVisible()){
29181 this.constrainXY();
29182 this.adjustAssets();
29184 this.fireEvent("resize", this, width, height);
29190 * Resizes the dialog to fit the specified content size.
29191 * @param {Number} width
29192 * @param {Number} height
29193 * @return {Roo.BasicDialog} this
29195 setContentSize : function(w, h){
29196 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29197 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29198 //if(!this.el.isBorderBox()){
29199 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29200 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29203 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29204 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29206 this.resizeTo(w, h);
29211 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29212 * executed in response to a particular key being pressed while the dialog is active.
29213 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29214 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29215 * @param {Function} fn The function to call
29216 * @param {Object} scope (optional) The scope of the function
29217 * @return {Roo.BasicDialog} this
29219 addKeyListener : function(key, fn, scope){
29220 var keyCode, shift, ctrl, alt;
29221 if(typeof key == "object" && !(key instanceof Array)){
29222 keyCode = key["key"];
29223 shift = key["shift"];
29224 ctrl = key["ctrl"];
29229 var handler = function(dlg, e){
29230 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29231 var k = e.getKey();
29232 if(keyCode instanceof Array){
29233 for(var i = 0, len = keyCode.length; i < len; i++){
29234 if(keyCode[i] == k){
29235 fn.call(scope || window, dlg, k, e);
29241 fn.call(scope || window, dlg, k, e);
29246 this.on("keydown", handler);
29251 * Returns the TabPanel component (creates it if it doesn't exist).
29252 * Note: If you wish to simply check for the existence of tabs without creating them,
29253 * check for a null 'tabs' property.
29254 * @return {Roo.TabPanel} The tabs component
29256 getTabs : function(){
29258 this.el.addClass("x-dlg-auto-tabs");
29259 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29260 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29266 * Adds a button to the footer section of the dialog.
29267 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29268 * object or a valid Roo.DomHelper element config
29269 * @param {Function} handler The function called when the button is clicked
29270 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29271 * @return {Roo.Button} The new button
29273 addButton : function(config, handler, scope){
29274 var dh = Roo.DomHelper;
29276 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29278 if(!this.btnContainer){
29279 var tb = this.footer.createChild({
29281 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29282 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29284 this.btnContainer = tb.firstChild.firstChild.firstChild;
29289 minWidth: this.minButtonWidth,
29292 if(typeof config == "string"){
29293 bconfig.text = config;
29296 bconfig.dhconfig = config;
29298 Roo.apply(bconfig, config);
29302 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29303 bconfig.position = Math.max(0, bconfig.position);
29304 fc = this.btnContainer.childNodes[bconfig.position];
29307 var btn = new Roo.Button(
29309 this.btnContainer.insertBefore(document.createElement("td"),fc)
29310 : this.btnContainer.appendChild(document.createElement("td")),
29311 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29314 this.syncBodyHeight();
29317 * Array of all the buttons that have been added to this dialog via addButton
29322 this.buttons.push(btn);
29327 * Sets the default button to be focused when the dialog is displayed.
29328 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29329 * @return {Roo.BasicDialog} this
29331 setDefaultButton : function(btn){
29332 this.defaultButton = btn;
29337 getHeaderFooterHeight : function(safe){
29340 height += this.header.getHeight();
29343 var fm = this.footer.getMargins();
29344 height += (this.footer.getHeight()+fm.top+fm.bottom);
29346 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29347 height += this.centerBg.getPadding("tb");
29352 syncBodyHeight : function(){
29353 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29354 var height = this.size.height - this.getHeaderFooterHeight(false);
29355 bd.setHeight(height-bd.getMargins("tb"));
29356 var hh = this.header.getHeight();
29357 var h = this.size.height-hh;
29359 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29360 bw.setHeight(h-cb.getPadding("tb"));
29361 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29362 bd.setWidth(bw.getWidth(true));
29364 this.tabs.syncHeight();
29366 this.tabs.el.repaint();
29372 * Restores the previous state of the dialog if Roo.state is configured.
29373 * @return {Roo.BasicDialog} this
29375 restoreState : function(){
29376 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29377 if(box && box.width){
29378 this.xy = [box.x, box.y];
29379 this.resizeTo(box.width, box.height);
29385 beforeShow : function(){
29387 if(this.fixedcenter){
29388 this.xy = this.el.getCenterXY(true);
29391 Roo.get(document.body).addClass("x-body-masked");
29392 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29395 this.constrainXY();
29399 animShow : function(){
29400 var b = Roo.get(this.animateTarget).getBox();
29401 this.proxy.setSize(b.width, b.height);
29402 this.proxy.setLocation(b.x, b.y);
29404 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29405 true, .35, this.showEl.createDelegate(this));
29409 * Shows the dialog.
29410 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29411 * @return {Roo.BasicDialog} this
29413 show : function(animateTarget){
29414 if (this.fireEvent("beforeshow", this) === false){
29417 if(this.syncHeightBeforeShow){
29418 this.syncBodyHeight();
29419 }else if(this.firstShow){
29420 this.firstShow = false;
29421 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29423 this.animateTarget = animateTarget || this.animateTarget;
29424 if(!this.el.isVisible()){
29426 if(this.animateTarget && Roo.get(this.animateTarget)){
29436 showEl : function(){
29438 this.el.setXY(this.xy);
29440 this.adjustAssets(true);
29443 // IE peekaboo bug - fix found by Dave Fenwick
29447 this.fireEvent("show", this);
29451 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29452 * dialog itself will receive focus.
29454 focus : function(){
29455 if(this.defaultButton){
29456 this.defaultButton.focus();
29458 this.focusEl.focus();
29463 constrainXY : function(){
29464 if(this.constraintoviewport !== false){
29465 if(!this.viewSize){
29466 if(this.container){
29467 var s = this.container.getSize();
29468 this.viewSize = [s.width, s.height];
29470 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29473 var s = Roo.get(this.container||document).getScroll();
29475 var x = this.xy[0], y = this.xy[1];
29476 var w = this.size.width, h = this.size.height;
29477 var vw = this.viewSize[0], vh = this.viewSize[1];
29478 // only move it if it needs it
29480 // first validate right/bottom
29481 if(x + w > vw+s.left){
29485 if(y + h > vh+s.top){
29489 // then make sure top/left isn't negative
29501 if(this.isVisible()){
29502 this.el.setLocation(x, y);
29503 this.adjustAssets();
29510 onDrag : function(){
29511 if(!this.proxyDrag){
29512 this.xy = this.el.getXY();
29513 this.adjustAssets();
29518 adjustAssets : function(doShow){
29519 var x = this.xy[0], y = this.xy[1];
29520 var w = this.size.width, h = this.size.height;
29521 if(doShow === true){
29523 this.shadow.show(this.el);
29529 if(this.shadow && this.shadow.isVisible()){
29530 this.shadow.show(this.el);
29532 if(this.shim && this.shim.isVisible()){
29533 this.shim.setBounds(x, y, w, h);
29538 adjustViewport : function(w, h){
29540 w = Roo.lib.Dom.getViewWidth();
29541 h = Roo.lib.Dom.getViewHeight();
29544 this.viewSize = [w, h];
29545 if(this.modal && this.mask.isVisible()){
29546 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29547 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29549 if(this.isVisible()){
29550 this.constrainXY();
29555 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29556 * shadow, proxy, mask, etc.) Also removes all event listeners.
29557 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29559 destroy : function(removeEl){
29560 if(this.isVisible()){
29561 this.animateTarget = null;
29564 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29566 this.tabs.destroy(removeEl);
29579 for(var i = 0, len = this.buttons.length; i < len; i++){
29580 this.buttons[i].destroy();
29583 this.el.removeAllListeners();
29584 if(removeEl === true){
29585 this.el.update("");
29588 Roo.DialogManager.unregister(this);
29592 startMove : function(){
29593 if(this.proxyDrag){
29596 if(this.constraintoviewport !== false){
29597 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29602 endMove : function(){
29603 if(!this.proxyDrag){
29604 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29606 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29609 this.refreshSize();
29610 this.adjustAssets();
29612 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29616 * Brings this dialog to the front of any other visible dialogs
29617 * @return {Roo.BasicDialog} this
29619 toFront : function(){
29620 Roo.DialogManager.bringToFront(this);
29625 * Sends this dialog to the back (under) of any other visible dialogs
29626 * @return {Roo.BasicDialog} this
29628 toBack : function(){
29629 Roo.DialogManager.sendToBack(this);
29634 * Centers this dialog in the viewport
29635 * @return {Roo.BasicDialog} this
29637 center : function(){
29638 var xy = this.el.getCenterXY(true);
29639 this.moveTo(xy[0], xy[1]);
29644 * Moves the dialog's top-left corner to the specified point
29645 * @param {Number} x
29646 * @param {Number} y
29647 * @return {Roo.BasicDialog} this
29649 moveTo : function(x, y){
29651 if(this.isVisible()){
29652 this.el.setXY(this.xy);
29653 this.adjustAssets();
29659 * Aligns the dialog to the specified element
29660 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29661 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29662 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29663 * @return {Roo.BasicDialog} this
29665 alignTo : function(element, position, offsets){
29666 this.xy = this.el.getAlignToXY(element, position, offsets);
29667 if(this.isVisible()){
29668 this.el.setXY(this.xy);
29669 this.adjustAssets();
29675 * Anchors an element to another element and realigns it when the window is resized.
29676 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29677 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29678 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29679 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29680 * is a number, it is used as the buffer delay (defaults to 50ms).
29681 * @return {Roo.BasicDialog} this
29683 anchorTo : function(el, alignment, offsets, monitorScroll){
29684 var action = function(){
29685 this.alignTo(el, alignment, offsets);
29687 Roo.EventManager.onWindowResize(action, this);
29688 var tm = typeof monitorScroll;
29689 if(tm != 'undefined'){
29690 Roo.EventManager.on(window, 'scroll', action, this,
29691 {buffer: tm == 'number' ? monitorScroll : 50});
29698 * Returns true if the dialog is visible
29699 * @return {Boolean}
29701 isVisible : function(){
29702 return this.el.isVisible();
29706 animHide : function(callback){
29707 var b = Roo.get(this.animateTarget).getBox();
29709 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29711 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29712 this.hideEl.createDelegate(this, [callback]));
29716 * Hides the dialog.
29717 * @param {Function} callback (optional) Function to call when the dialog is hidden
29718 * @return {Roo.BasicDialog} this
29720 hide : function(callback){
29721 if (this.fireEvent("beforehide", this) === false){
29725 this.shadow.hide();
29730 // sometimes animateTarget seems to get set.. causing problems...
29731 // this just double checks..
29732 if(this.animateTarget && Roo.get(this.animateTarget)) {
29733 this.animHide(callback);
29736 this.hideEl(callback);
29742 hideEl : function(callback){
29746 Roo.get(document.body).removeClass("x-body-masked");
29748 this.fireEvent("hide", this);
29749 if(typeof callback == "function"){
29755 hideAction : function(){
29756 this.setLeft("-10000px");
29757 this.setTop("-10000px");
29758 this.setStyle("visibility", "hidden");
29762 refreshSize : function(){
29763 this.size = this.el.getSize();
29764 this.xy = this.el.getXY();
29765 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29769 // z-index is managed by the DialogManager and may be overwritten at any time
29770 setZIndex : function(index){
29772 this.mask.setStyle("z-index", index);
29775 this.shim.setStyle("z-index", ++index);
29778 this.shadow.setZIndex(++index);
29780 this.el.setStyle("z-index", ++index);
29782 this.proxy.setStyle("z-index", ++index);
29785 this.resizer.proxy.setStyle("z-index", ++index);
29788 this.lastZIndex = index;
29792 * Returns the element for this dialog
29793 * @return {Roo.Element} The underlying dialog Element
29795 getEl : function(){
29801 * @class Roo.DialogManager
29802 * Provides global access to BasicDialogs that have been created and
29803 * support for z-indexing (layering) multiple open dialogs.
29805 Roo.DialogManager = function(){
29807 var accessList = [];
29811 var sortDialogs = function(d1, d2){
29812 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29816 var orderDialogs = function(){
29817 accessList.sort(sortDialogs);
29818 var seed = Roo.DialogManager.zseed;
29819 for(var i = 0, len = accessList.length; i < len; i++){
29820 var dlg = accessList[i];
29822 dlg.setZIndex(seed + (i*10));
29829 * The starting z-index for BasicDialogs (defaults to 9000)
29830 * @type Number The z-index value
29835 register : function(dlg){
29836 list[dlg.id] = dlg;
29837 accessList.push(dlg);
29841 unregister : function(dlg){
29842 delete list[dlg.id];
29845 if(!accessList.indexOf){
29846 for( i = 0, len = accessList.length; i < len; i++){
29847 if(accessList[i] == dlg){
29848 accessList.splice(i, 1);
29853 i = accessList.indexOf(dlg);
29855 accessList.splice(i, 1);
29861 * Gets a registered dialog by id
29862 * @param {String/Object} id The id of the dialog or a dialog
29863 * @return {Roo.BasicDialog} this
29865 get : function(id){
29866 return typeof id == "object" ? id : list[id];
29870 * Brings the specified dialog to the front
29871 * @param {String/Object} dlg The id of the dialog or a dialog
29872 * @return {Roo.BasicDialog} this
29874 bringToFront : function(dlg){
29875 dlg = this.get(dlg);
29878 dlg._lastAccess = new Date().getTime();
29885 * Sends the specified dialog to the back
29886 * @param {String/Object} dlg The id of the dialog or a dialog
29887 * @return {Roo.BasicDialog} this
29889 sendToBack : function(dlg){
29890 dlg = this.get(dlg);
29891 dlg._lastAccess = -(new Date().getTime());
29897 * Hides all dialogs
29899 hideAll : function(){
29900 for(var id in list){
29901 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29910 * @class Roo.LayoutDialog
29911 * @extends Roo.BasicDialog
29912 * Dialog which provides adjustments for working with a layout in a Dialog.
29913 * Add your necessary layout config options to the dialog's config.<br>
29914 * Example usage (including a nested layout):
29917 dialog = new Roo.LayoutDialog("download-dlg", {
29926 // layout config merges with the dialog config
29928 tabPosition: "top",
29929 alwaysShowTabs: true
29932 dialog.addKeyListener(27, dialog.hide, dialog);
29933 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29934 dialog.addButton("Build It!", this.getDownload, this);
29936 // we can even add nested layouts
29937 var innerLayout = new Roo.BorderLayout("dl-inner", {
29947 innerLayout.beginUpdate();
29948 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29949 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29950 innerLayout.endUpdate(true);
29952 var layout = dialog.getLayout();
29953 layout.beginUpdate();
29954 layout.add("center", new Roo.ContentPanel("standard-panel",
29955 {title: "Download the Source", fitToFrame:true}));
29956 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29957 {title: "Build your own roo.js"}));
29958 layout.getRegion("center").showPanel(sp);
29959 layout.endUpdate();
29963 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29964 * @param {Object} config configuration options
29966 Roo.LayoutDialog = function(el, cfg){
29969 if (typeof(cfg) == 'undefined') {
29970 config = Roo.apply({}, el);
29971 // not sure why we use documentElement here.. - it should always be body.
29972 // IE7 borks horribly if we use documentElement.
29973 // webkit also does not like documentElement - it creates a body element...
29974 el = Roo.get( document.body || document.documentElement ).createChild();
29975 //config.autoCreate = true;
29979 config.autoTabs = false;
29980 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29981 this.body.setStyle({overflow:"hidden", position:"relative"});
29982 this.layout = new Roo.BorderLayout(this.body.dom, config);
29983 this.layout.monitorWindowResize = false;
29984 this.el.addClass("x-dlg-auto-layout");
29985 // fix case when center region overwrites center function
29986 this.center = Roo.BasicDialog.prototype.center;
29987 this.on("show", this.layout.layout, this.layout, true);
29988 if (config.items) {
29989 var xitems = config.items;
29990 delete config.items;
29991 Roo.each(xitems, this.addxtype, this);
29996 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29998 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30001 endUpdate : function(){
30002 this.layout.endUpdate();
30006 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30009 beginUpdate : function(){
30010 this.layout.beginUpdate();
30014 * Get the BorderLayout for this dialog
30015 * @return {Roo.BorderLayout}
30017 getLayout : function(){
30018 return this.layout;
30021 showEl : function(){
30022 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30024 this.layout.layout();
30029 // Use the syncHeightBeforeShow config option to control this automatically
30030 syncBodyHeight : function(){
30031 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30032 if(this.layout){this.layout.layout();}
30036 * Add an xtype element (actually adds to the layout.)
30037 * @return {Object} xdata xtype object data.
30040 addxtype : function(c) {
30041 return this.layout.addxtype(c);
30045 * Ext JS Library 1.1.1
30046 * Copyright(c) 2006-2007, Ext JS, LLC.
30048 * Originally Released Under LGPL - original licence link has changed is not relivant.
30051 * <script type="text/javascript">
30055 * @class Roo.MessageBox
30056 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30060 Roo.Msg.alert('Status', 'Changes saved successfully.');
30062 // Prompt for user data:
30063 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30065 // process text value...
30069 // Show a dialog using config options:
30071 title:'Save Changes?',
30072 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30073 buttons: Roo.Msg.YESNOCANCEL,
30080 Roo.MessageBox = function(){
30081 var dlg, opt, mask, waitTimer;
30082 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30083 var buttons, activeTextEl, bwidth;
30086 var handleButton = function(button){
30088 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30092 var handleHide = function(){
30093 if(opt && opt.cls){
30094 dlg.el.removeClass(opt.cls);
30097 Roo.TaskMgr.stop(waitTimer);
30103 var updateButtons = function(b){
30106 buttons["ok"].hide();
30107 buttons["cancel"].hide();
30108 buttons["yes"].hide();
30109 buttons["no"].hide();
30110 dlg.footer.dom.style.display = 'none';
30113 dlg.footer.dom.style.display = '';
30114 for(var k in buttons){
30115 if(typeof buttons[k] != "function"){
30118 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30119 width += buttons[k].el.getWidth()+15;
30129 var handleEsc = function(d, k, e){
30130 if(opt && opt.closable !== false){
30140 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30141 * @return {Roo.BasicDialog} The BasicDialog element
30143 getDialog : function(){
30145 dlg = new Roo.BasicDialog("x-msg-box", {
30150 constraintoviewport:false,
30152 collapsible : false,
30155 width:400, height:100,
30156 buttonAlign:"center",
30157 closeClick : function(){
30158 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30159 handleButton("no");
30161 handleButton("cancel");
30165 dlg.on("hide", handleHide);
30167 dlg.addKeyListener(27, handleEsc);
30169 var bt = this.buttonText;
30170 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30171 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30172 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30173 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30174 bodyEl = dlg.body.createChild({
30176 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>'
30178 msgEl = bodyEl.dom.firstChild;
30179 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30180 textboxEl.enableDisplayMode();
30181 textboxEl.addKeyListener([10,13], function(){
30182 if(dlg.isVisible() && opt && opt.buttons){
30183 if(opt.buttons.ok){
30184 handleButton("ok");
30185 }else if(opt.buttons.yes){
30186 handleButton("yes");
30190 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30191 textareaEl.enableDisplayMode();
30192 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30193 progressEl.enableDisplayMode();
30194 var pf = progressEl.dom.firstChild;
30196 pp = Roo.get(pf.firstChild);
30197 pp.setHeight(pf.offsetHeight);
30205 * Updates the message box body text
30206 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30207 * the XHTML-compliant non-breaking space character '&#160;')
30208 * @return {Roo.MessageBox} This message box
30210 updateText : function(text){
30211 if(!dlg.isVisible() && !opt.width){
30212 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30214 msgEl.innerHTML = text || ' ';
30216 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30217 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30219 Math.min(opt.width || cw , this.maxWidth),
30220 Math.max(opt.minWidth || this.minWidth, bwidth)
30223 activeTextEl.setWidth(w);
30225 if(dlg.isVisible()){
30226 dlg.fixedcenter = false;
30228 // to big, make it scroll. = But as usual stupid IE does not support
30231 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30232 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30233 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30235 bodyEl.dom.style.height = '';
30236 bodyEl.dom.style.overflowY = '';
30239 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30241 bodyEl.dom.style.overflowX = '';
30244 dlg.setContentSize(w, bodyEl.getHeight());
30245 if(dlg.isVisible()){
30246 dlg.fixedcenter = true;
30252 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30253 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30254 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30255 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30256 * @return {Roo.MessageBox} This message box
30258 updateProgress : function(value, text){
30260 this.updateText(text);
30262 if (pp) { // weird bug on my firefox - for some reason this is not defined
30263 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30269 * Returns true if the message box is currently displayed
30270 * @return {Boolean} True if the message box is visible, else false
30272 isVisible : function(){
30273 return dlg && dlg.isVisible();
30277 * Hides the message box if it is displayed
30280 if(this.isVisible()){
30286 * Displays a new message box, or reinitializes an existing message box, based on the config options
30287 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30288 * The following config object properties are supported:
30290 Property Type Description
30291 ---------- --------------- ------------------------------------------------------------------------------------
30292 animEl String/Element An id or Element from which the message box should animate as it opens and
30293 closes (defaults to undefined)
30294 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30295 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30296 closable Boolean False to hide the top-right close button (defaults to true). Note that
30297 progress and wait dialogs will ignore this property and always hide the
30298 close button as they can only be closed programmatically.
30299 cls String A custom CSS class to apply to the message box element
30300 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30301 displayed (defaults to 75)
30302 fn Function A callback function to execute after closing the dialog. The arguments to the
30303 function will be btn (the name of the button that was clicked, if applicable,
30304 e.g. "ok"), and text (the value of the active text field, if applicable).
30305 Progress and wait dialogs will ignore this option since they do not respond to
30306 user actions and can only be closed programmatically, so any required function
30307 should be called by the same code after it closes the dialog.
30308 icon String A CSS class that provides a background image to be used as an icon for
30309 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30310 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30311 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30312 modal Boolean False to allow user interaction with the page while the message box is
30313 displayed (defaults to true)
30314 msg String A string that will replace the existing message box body text (defaults
30315 to the XHTML-compliant non-breaking space character ' ')
30316 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30317 progress Boolean True to display a progress bar (defaults to false)
30318 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30319 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30320 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30321 title String The title text
30322 value String The string value to set into the active textbox element if displayed
30323 wait Boolean True to display a progress bar (defaults to false)
30324 width Number The width of the dialog in pixels
30331 msg: 'Please enter your address:',
30333 buttons: Roo.MessageBox.OKCANCEL,
30336 animEl: 'addAddressBtn'
30339 * @param {Object} config Configuration options
30340 * @return {Roo.MessageBox} This message box
30342 show : function(options)
30345 // this causes nightmares if you show one dialog after another
30346 // especially on callbacks..
30348 if(this.isVisible()){
30351 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30352 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30353 Roo.log("New Dialog Message:" + options.msg )
30354 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30355 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30358 var d = this.getDialog();
30360 d.setTitle(opt.title || " ");
30361 d.close.setDisplayed(opt.closable !== false);
30362 activeTextEl = textboxEl;
30363 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30368 textareaEl.setHeight(typeof opt.multiline == "number" ?
30369 opt.multiline : this.defaultTextHeight);
30370 activeTextEl = textareaEl;
30379 progressEl.setDisplayed(opt.progress === true);
30380 this.updateProgress(0);
30381 activeTextEl.dom.value = opt.value || "";
30383 dlg.setDefaultButton(activeTextEl);
30385 var bs = opt.buttons;
30388 db = buttons["ok"];
30389 }else if(bs && bs.yes){
30390 db = buttons["yes"];
30392 dlg.setDefaultButton(db);
30394 bwidth = updateButtons(opt.buttons);
30395 this.updateText(opt.msg);
30397 d.el.addClass(opt.cls);
30399 d.proxyDrag = opt.proxyDrag === true;
30400 d.modal = opt.modal !== false;
30401 d.mask = opt.modal !== false ? mask : false;
30402 if(!d.isVisible()){
30403 // force it to the end of the z-index stack so it gets a cursor in FF
30404 document.body.appendChild(dlg.el.dom);
30405 d.animateTarget = null;
30406 d.show(options.animEl);
30412 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30413 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30414 * and closing the message box when the process is complete.
30415 * @param {String} title The title bar text
30416 * @param {String} msg The message box body text
30417 * @return {Roo.MessageBox} This message box
30419 progress : function(title, msg){
30426 minWidth: this.minProgressWidth,
30433 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30434 * If a callback function is passed it will be called after the user clicks the button, and the
30435 * id of the button that was clicked will be passed as the only parameter to the callback
30436 * (could also be the top-right close button).
30437 * @param {String} title The title bar text
30438 * @param {String} msg The message box body text
30439 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30440 * @param {Object} scope (optional) The scope of the callback function
30441 * @return {Roo.MessageBox} This message box
30443 alert : function(title, msg, fn, scope){
30456 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30457 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30458 * You are responsible for closing the message box when the process is complete.
30459 * @param {String} msg The message box body text
30460 * @param {String} title (optional) The title bar text
30461 * @return {Roo.MessageBox} This message box
30463 wait : function(msg, title){
30474 waitTimer = Roo.TaskMgr.start({
30476 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30484 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30485 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30486 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30487 * @param {String} title The title bar text
30488 * @param {String} msg The message box body text
30489 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30490 * @param {Object} scope (optional) The scope of the callback function
30491 * @return {Roo.MessageBox} This message box
30493 confirm : function(title, msg, fn, scope){
30497 buttons: this.YESNO,
30506 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30507 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30508 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30509 * (could also be the top-right close button) and the text that was entered will be passed as the two
30510 * parameters to the callback.
30511 * @param {String} title The title bar text
30512 * @param {String} msg The message box body text
30513 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30514 * @param {Object} scope (optional) The scope of the callback function
30515 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30516 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30517 * @return {Roo.MessageBox} This message box
30519 prompt : function(title, msg, fn, scope, multiline){
30523 buttons: this.OKCANCEL,
30528 multiline: multiline,
30535 * Button config that displays a single OK button
30540 * Button config that displays Yes and No buttons
30543 YESNO : {yes:true, no:true},
30545 * Button config that displays OK and Cancel buttons
30548 OKCANCEL : {ok:true, cancel:true},
30550 * Button config that displays Yes, No and Cancel buttons
30553 YESNOCANCEL : {yes:true, no:true, cancel:true},
30556 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30559 defaultTextHeight : 75,
30561 * The maximum width in pixels of the message box (defaults to 600)
30566 * The minimum width in pixels of the message box (defaults to 100)
30571 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30572 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30575 minProgressWidth : 250,
30577 * An object containing the default button text strings that can be overriden for localized language support.
30578 * Supported properties are: ok, cancel, yes and no.
30579 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30592 * Shorthand for {@link Roo.MessageBox}
30594 Roo.Msg = Roo.MessageBox;/*
30596 * Ext JS Library 1.1.1
30597 * Copyright(c) 2006-2007, Ext JS, LLC.
30599 * Originally Released Under LGPL - original licence link has changed is not relivant.
30602 * <script type="text/javascript">
30605 * @class Roo.QuickTips
30606 * Provides attractive and customizable tooltips for any element.
30609 Roo.QuickTips = function(){
30610 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30611 var ce, bd, xy, dd;
30612 var visible = false, disabled = true, inited = false;
30613 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30615 var onOver = function(e){
30619 var t = e.getTarget();
30620 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30623 if(ce && t == ce.el){
30624 clearTimeout(hideProc);
30627 if(t && tagEls[t.id]){
30628 tagEls[t.id].el = t;
30629 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30632 var ttp, et = Roo.fly(t);
30633 var ns = cfg.namespace;
30634 if(tm.interceptTitles && t.title){
30637 t.removeAttribute("title");
30638 e.preventDefault();
30640 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30643 showProc = show.defer(tm.showDelay, tm, [{
30646 width: et.getAttributeNS(ns, cfg.width),
30647 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30648 title: et.getAttributeNS(ns, cfg.title),
30649 cls: et.getAttributeNS(ns, cfg.cls)
30654 var onOut = function(e){
30655 clearTimeout(showProc);
30656 var t = e.getTarget();
30657 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30658 hideProc = setTimeout(hide, tm.hideDelay);
30662 var onMove = function(e){
30668 if(tm.trackMouse && ce){
30673 var onDown = function(e){
30674 clearTimeout(showProc);
30675 clearTimeout(hideProc);
30677 if(tm.hideOnClick){
30680 tm.enable.defer(100, tm);
30685 var getPad = function(){
30686 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30689 var show = function(o){
30693 clearTimeout(dismissProc);
30695 if(removeCls){ // in case manually hidden
30696 el.removeClass(removeCls);
30700 el.addClass(ce.cls);
30701 removeCls = ce.cls;
30704 tipTitle.update(ce.title);
30707 tipTitle.update('');
30710 el.dom.style.width = tm.maxWidth+'px';
30711 //tipBody.dom.style.width = '';
30712 tipBodyText.update(o.text);
30713 var p = getPad(), w = ce.width;
30715 var td = tipBodyText.dom;
30716 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30717 if(aw > tm.maxWidth){
30719 }else if(aw < tm.minWidth){
30725 //tipBody.setWidth(w);
30726 el.setWidth(parseInt(w, 10) + p);
30727 if(ce.autoHide === false){
30728 close.setDisplayed(true);
30733 close.setDisplayed(false);
30739 el.avoidY = xy[1]-18;
30744 el.setStyle("visibility", "visible");
30745 el.fadeIn({callback: afterShow});
30751 var afterShow = function(){
30755 if(tm.autoDismiss && ce.autoHide !== false){
30756 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30761 var hide = function(noanim){
30762 clearTimeout(dismissProc);
30763 clearTimeout(hideProc);
30765 if(el.isVisible()){
30767 if(noanim !== true && tm.animate){
30768 el.fadeOut({callback: afterHide});
30775 var afterHide = function(){
30778 el.removeClass(removeCls);
30785 * @cfg {Number} minWidth
30786 * The minimum width of the quick tip (defaults to 40)
30790 * @cfg {Number} maxWidth
30791 * The maximum width of the quick tip (defaults to 300)
30795 * @cfg {Boolean} interceptTitles
30796 * True to automatically use the element's DOM title value if available (defaults to false)
30798 interceptTitles : false,
30800 * @cfg {Boolean} trackMouse
30801 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30803 trackMouse : false,
30805 * @cfg {Boolean} hideOnClick
30806 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30808 hideOnClick : true,
30810 * @cfg {Number} showDelay
30811 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30815 * @cfg {Number} hideDelay
30816 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30820 * @cfg {Boolean} autoHide
30821 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30822 * Used in conjunction with hideDelay.
30827 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30828 * (defaults to true). Used in conjunction with autoDismissDelay.
30830 autoDismiss : true,
30833 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30835 autoDismissDelay : 5000,
30837 * @cfg {Boolean} animate
30838 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30843 * @cfg {String} title
30844 * Title text to display (defaults to ''). This can be any valid HTML markup.
30848 * @cfg {String} text
30849 * Body text to display (defaults to ''). This can be any valid HTML markup.
30853 * @cfg {String} cls
30854 * A CSS class to apply to the base quick tip element (defaults to '').
30858 * @cfg {Number} width
30859 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30860 * minWidth or maxWidth.
30865 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30866 * or display QuickTips in a page.
30869 tm = Roo.QuickTips;
30870 cfg = tm.tagConfig;
30872 if(!Roo.isReady){ // allow calling of init() before onReady
30873 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30876 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30877 el.fxDefaults = {stopFx: true};
30878 // maximum custom styling
30879 //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>');
30880 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>');
30881 tipTitle = el.child('h3');
30882 tipTitle.enableDisplayMode("block");
30883 tipBody = el.child('div.x-tip-bd');
30884 tipBodyText = el.child('div.x-tip-bd-inner');
30885 //bdLeft = el.child('div.x-tip-bd-left');
30886 //bdRight = el.child('div.x-tip-bd-right');
30887 close = el.child('div.x-tip-close');
30888 close.enableDisplayMode("block");
30889 close.on("click", hide);
30890 var d = Roo.get(document);
30891 d.on("mousedown", onDown);
30892 d.on("mouseover", onOver);
30893 d.on("mouseout", onOut);
30894 d.on("mousemove", onMove);
30895 esc = d.addKeyListener(27, hide);
30898 dd = el.initDD("default", null, {
30899 onDrag : function(){
30903 dd.setHandleElId(tipTitle.id);
30912 * Configures a new quick tip instance and assigns it to a target element. The following config options
30915 Property Type Description
30916 ---------- --------------------- ------------------------------------------------------------------------
30917 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30919 * @param {Object} config The config object
30921 register : function(config){
30922 var cs = config instanceof Array ? config : arguments;
30923 for(var i = 0, len = cs.length; i < len; i++) {
30925 var target = c.target;
30927 if(target instanceof Array){
30928 for(var j = 0, jlen = target.length; j < jlen; j++){
30929 tagEls[target[j]] = c;
30932 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30939 * Removes this quick tip from its element and destroys it.
30940 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30942 unregister : function(el){
30943 delete tagEls[Roo.id(el)];
30947 * Enable this quick tip.
30949 enable : function(){
30950 if(inited && disabled){
30952 if(locks.length < 1){
30959 * Disable this quick tip.
30961 disable : function(){
30963 clearTimeout(showProc);
30964 clearTimeout(hideProc);
30965 clearTimeout(dismissProc);
30973 * Returns true if the quick tip is enabled, else false.
30975 isEnabled : function(){
30982 attribute : "qtip",
30992 // backwards compat
30993 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30995 * Ext JS Library 1.1.1
30996 * Copyright(c) 2006-2007, Ext JS, LLC.
30998 * Originally Released Under LGPL - original licence link has changed is not relivant.
31001 * <script type="text/javascript">
31006 * @class Roo.tree.TreePanel
31007 * @extends Roo.data.Tree
31009 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31010 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31011 * @cfg {Boolean} enableDD true to enable drag and drop
31012 * @cfg {Boolean} enableDrag true to enable just drag
31013 * @cfg {Boolean} enableDrop true to enable just drop
31014 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31015 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31016 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31017 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31018 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31019 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31020 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31021 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31022 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31023 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31024 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31025 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31026 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31027 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31028 * @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>
31029 * @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>
31032 * @param {String/HTMLElement/Element} el The container element
31033 * @param {Object} config
31035 Roo.tree.TreePanel = function(el, config){
31037 var loader = false;
31039 root = config.root;
31040 delete config.root;
31042 if (config.loader) {
31043 loader = config.loader;
31044 delete config.loader;
31047 Roo.apply(this, config);
31048 Roo.tree.TreePanel.superclass.constructor.call(this);
31049 this.el = Roo.get(el);
31050 this.el.addClass('x-tree');
31051 //console.log(root);
31053 this.setRootNode( Roo.factory(root, Roo.tree));
31056 this.loader = Roo.factory(loader, Roo.tree);
31059 * Read-only. The id of the container element becomes this TreePanel's id.
31061 this.id = this.el.id;
31064 * @event beforeload
31065 * Fires before a node is loaded, return false to cancel
31066 * @param {Node} node The node being loaded
31068 "beforeload" : true,
31071 * Fires when a node is loaded
31072 * @param {Node} node The node that was loaded
31076 * @event textchange
31077 * Fires when the text for a node is changed
31078 * @param {Node} node The node
31079 * @param {String} text The new text
31080 * @param {String} oldText The old text
31082 "textchange" : true,
31084 * @event beforeexpand
31085 * Fires before a node is expanded, return false to cancel.
31086 * @param {Node} node The node
31087 * @param {Boolean} deep
31088 * @param {Boolean} anim
31090 "beforeexpand" : true,
31092 * @event beforecollapse
31093 * Fires before a node is collapsed, return false to cancel.
31094 * @param {Node} node The node
31095 * @param {Boolean} deep
31096 * @param {Boolean} anim
31098 "beforecollapse" : true,
31101 * Fires when a node is expanded
31102 * @param {Node} node The node
31106 * @event disabledchange
31107 * Fires when the disabled status of a node changes
31108 * @param {Node} node The node
31109 * @param {Boolean} disabled
31111 "disabledchange" : true,
31114 * Fires when a node is collapsed
31115 * @param {Node} node The node
31119 * @event beforeclick
31120 * Fires before click processing on a node. Return false to cancel the default action.
31121 * @param {Node} node The node
31122 * @param {Roo.EventObject} e The event object
31124 "beforeclick":true,
31126 * @event checkchange
31127 * Fires when a node with a checkbox's checked property changes
31128 * @param {Node} this This node
31129 * @param {Boolean} checked
31131 "checkchange":true,
31134 * Fires when a node is clicked
31135 * @param {Node} node The node
31136 * @param {Roo.EventObject} e The event object
31141 * Fires when a node is double clicked
31142 * @param {Node} node The node
31143 * @param {Roo.EventObject} e The event object
31147 * @event contextmenu
31148 * Fires when a node is right clicked
31149 * @param {Node} node The node
31150 * @param {Roo.EventObject} e The event object
31152 "contextmenu":true,
31154 * @event beforechildrenrendered
31155 * Fires right before the child nodes for a node are rendered
31156 * @param {Node} node The node
31158 "beforechildrenrendered":true,
31161 * Fires when a node starts being dragged
31162 * @param {Roo.tree.TreePanel} this
31163 * @param {Roo.tree.TreeNode} node
31164 * @param {event} e The raw browser event
31166 "startdrag" : true,
31169 * Fires when a drag operation is complete
31170 * @param {Roo.tree.TreePanel} this
31171 * @param {Roo.tree.TreeNode} node
31172 * @param {event} e The raw browser event
31177 * Fires when a dragged node is dropped on a valid DD target
31178 * @param {Roo.tree.TreePanel} this
31179 * @param {Roo.tree.TreeNode} node
31180 * @param {DD} dd The dd it was dropped on
31181 * @param {event} e The raw browser event
31185 * @event beforenodedrop
31186 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31187 * passed to handlers has the following properties:<br />
31188 * <ul style="padding:5px;padding-left:16px;">
31189 * <li>tree - The TreePanel</li>
31190 * <li>target - The node being targeted for the drop</li>
31191 * <li>data - The drag data from the drag source</li>
31192 * <li>point - The point of the drop - append, above or below</li>
31193 * <li>source - The drag source</li>
31194 * <li>rawEvent - Raw mouse event</li>
31195 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31196 * to be inserted by setting them on this object.</li>
31197 * <li>cancel - Set this to true to cancel the drop.</li>
31199 * @param {Object} dropEvent
31201 "beforenodedrop" : true,
31204 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31205 * passed to handlers has the following properties:<br />
31206 * <ul style="padding:5px;padding-left:16px;">
31207 * <li>tree - The TreePanel</li>
31208 * <li>target - The node being targeted for the drop</li>
31209 * <li>data - The drag data from the drag source</li>
31210 * <li>point - The point of the drop - append, above or below</li>
31211 * <li>source - The drag source</li>
31212 * <li>rawEvent - Raw mouse event</li>
31213 * <li>dropNode - Dropped node(s).</li>
31215 * @param {Object} dropEvent
31219 * @event nodedragover
31220 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31221 * passed to handlers has the following properties:<br />
31222 * <ul style="padding:5px;padding-left:16px;">
31223 * <li>tree - The TreePanel</li>
31224 * <li>target - The node being targeted for the drop</li>
31225 * <li>data - The drag data from the drag source</li>
31226 * <li>point - The point of the drop - append, above or below</li>
31227 * <li>source - The drag source</li>
31228 * <li>rawEvent - Raw mouse event</li>
31229 * <li>dropNode - Drop node(s) provided by the source.</li>
31230 * <li>cancel - Set this to true to signal drop not allowed.</li>
31232 * @param {Object} dragOverEvent
31234 "nodedragover" : true
31237 if(this.singleExpand){
31238 this.on("beforeexpand", this.restrictExpand, this);
31241 this.editor.tree = this;
31242 this.editor = Roo.factory(this.editor, Roo.tree);
31245 if (this.selModel) {
31246 this.selModel = Roo.factory(this.selModel, Roo.tree);
31250 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31251 rootVisible : true,
31252 animate: Roo.enableFx,
31255 hlDrop : Roo.enableFx,
31259 rendererTip: false,
31261 restrictExpand : function(node){
31262 var p = node.parentNode;
31264 if(p.expandedChild && p.expandedChild.parentNode == p){
31265 p.expandedChild.collapse();
31267 p.expandedChild = node;
31271 // private override
31272 setRootNode : function(node){
31273 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31274 if(!this.rootVisible){
31275 node.ui = new Roo.tree.RootTreeNodeUI(node);
31281 * Returns the container element for this TreePanel
31283 getEl : function(){
31288 * Returns the default TreeLoader for this TreePanel
31290 getLoader : function(){
31291 return this.loader;
31297 expandAll : function(){
31298 this.root.expand(true);
31302 * Collapse all nodes
31304 collapseAll : function(){
31305 this.root.collapse(true);
31309 * Returns the selection model used by this TreePanel
31311 getSelectionModel : function(){
31312 if(!this.selModel){
31313 this.selModel = new Roo.tree.DefaultSelectionModel();
31315 return this.selModel;
31319 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31320 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31321 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31324 getChecked : function(a, startNode){
31325 startNode = startNode || this.root;
31327 var f = function(){
31328 if(this.attributes.checked){
31329 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31332 startNode.cascade(f);
31337 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31338 * @param {String} path
31339 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31340 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31341 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31343 expandPath : function(path, attr, callback){
31344 attr = attr || "id";
31345 var keys = path.split(this.pathSeparator);
31346 var curNode = this.root;
31347 if(curNode.attributes[attr] != keys[1]){ // invalid root
31349 callback(false, null);
31354 var f = function(){
31355 if(++index == keys.length){
31357 callback(true, curNode);
31361 var c = curNode.findChild(attr, keys[index]);
31364 callback(false, curNode);
31369 c.expand(false, false, f);
31371 curNode.expand(false, false, f);
31375 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31376 * @param {String} path
31377 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31378 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31379 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31381 selectPath : function(path, attr, callback){
31382 attr = attr || "id";
31383 var keys = path.split(this.pathSeparator);
31384 var v = keys.pop();
31385 if(keys.length > 0){
31386 var f = function(success, node){
31387 if(success && node){
31388 var n = node.findChild(attr, v);
31394 }else if(callback){
31395 callback(false, n);
31399 callback(false, n);
31403 this.expandPath(keys.join(this.pathSeparator), attr, f);
31405 this.root.select();
31407 callback(true, this.root);
31412 getTreeEl : function(){
31417 * Trigger rendering of this TreePanel
31419 render : function(){
31420 if (this.innerCt) {
31421 return this; // stop it rendering more than once!!
31424 this.innerCt = this.el.createChild({tag:"ul",
31425 cls:"x-tree-root-ct " +
31426 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31428 if(this.containerScroll){
31429 Roo.dd.ScrollManager.register(this.el);
31431 if((this.enableDD || this.enableDrop) && !this.dropZone){
31433 * The dropZone used by this tree if drop is enabled
31434 * @type Roo.tree.TreeDropZone
31436 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31437 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31440 if((this.enableDD || this.enableDrag) && !this.dragZone){
31442 * The dragZone used by this tree if drag is enabled
31443 * @type Roo.tree.TreeDragZone
31445 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31446 ddGroup: this.ddGroup || "TreeDD",
31447 scroll: this.ddScroll
31450 this.getSelectionModel().init(this);
31452 Roo.log("ROOT not set in tree");
31455 this.root.render();
31456 if(!this.rootVisible){
31457 this.root.renderChildren();
31463 * Ext JS Library 1.1.1
31464 * Copyright(c) 2006-2007, Ext JS, LLC.
31466 * Originally Released Under LGPL - original licence link has changed is not relivant.
31469 * <script type="text/javascript">
31474 * @class Roo.tree.DefaultSelectionModel
31475 * @extends Roo.util.Observable
31476 * The default single selection for a TreePanel.
31477 * @param {Object} cfg Configuration
31479 Roo.tree.DefaultSelectionModel = function(cfg){
31480 this.selNode = null;
31486 * @event selectionchange
31487 * Fires when the selected node changes
31488 * @param {DefaultSelectionModel} this
31489 * @param {TreeNode} node the new selection
31491 "selectionchange" : true,
31494 * @event beforeselect
31495 * Fires before the selected node changes, return false to cancel the change
31496 * @param {DefaultSelectionModel} this
31497 * @param {TreeNode} node the new selection
31498 * @param {TreeNode} node the old selection
31500 "beforeselect" : true
31503 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31506 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31507 init : function(tree){
31509 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31510 tree.on("click", this.onNodeClick, this);
31513 onNodeClick : function(node, e){
31514 if (e.ctrlKey && this.selNode == node) {
31515 this.unselect(node);
31523 * @param {TreeNode} node The node to select
31524 * @return {TreeNode} The selected node
31526 select : function(node){
31527 var last = this.selNode;
31528 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31530 last.ui.onSelectedChange(false);
31532 this.selNode = node;
31533 node.ui.onSelectedChange(true);
31534 this.fireEvent("selectionchange", this, node, last);
31541 * @param {TreeNode} node The node to unselect
31543 unselect : function(node){
31544 if(this.selNode == node){
31545 this.clearSelections();
31550 * Clear all selections
31552 clearSelections : function(){
31553 var n = this.selNode;
31555 n.ui.onSelectedChange(false);
31556 this.selNode = null;
31557 this.fireEvent("selectionchange", this, null);
31563 * Get the selected node
31564 * @return {TreeNode} The selected node
31566 getSelectedNode : function(){
31567 return this.selNode;
31571 * Returns true if the node is selected
31572 * @param {TreeNode} node The node to check
31573 * @return {Boolean}
31575 isSelected : function(node){
31576 return this.selNode == node;
31580 * Selects the node above the selected node in the tree, intelligently walking the nodes
31581 * @return TreeNode The new selection
31583 selectPrevious : function(){
31584 var s = this.selNode || this.lastSelNode;
31588 var ps = s.previousSibling;
31590 if(!ps.isExpanded() || ps.childNodes.length < 1){
31591 return this.select(ps);
31593 var lc = ps.lastChild;
31594 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31597 return this.select(lc);
31599 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31600 return this.select(s.parentNode);
31606 * Selects the node above the selected node in the tree, intelligently walking the nodes
31607 * @return TreeNode The new selection
31609 selectNext : function(){
31610 var s = this.selNode || this.lastSelNode;
31614 if(s.firstChild && s.isExpanded()){
31615 return this.select(s.firstChild);
31616 }else if(s.nextSibling){
31617 return this.select(s.nextSibling);
31618 }else if(s.parentNode){
31620 s.parentNode.bubble(function(){
31621 if(this.nextSibling){
31622 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31631 onKeyDown : function(e){
31632 var s = this.selNode || this.lastSelNode;
31633 // undesirable, but required
31638 var k = e.getKey();
31646 this.selectPrevious();
31649 e.preventDefault();
31650 if(s.hasChildNodes()){
31651 if(!s.isExpanded()){
31653 }else if(s.firstChild){
31654 this.select(s.firstChild, e);
31659 e.preventDefault();
31660 if(s.hasChildNodes() && s.isExpanded()){
31662 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31663 this.select(s.parentNode, e);
31671 * @class Roo.tree.MultiSelectionModel
31672 * @extends Roo.util.Observable
31673 * Multi selection for a TreePanel.
31674 * @param {Object} cfg Configuration
31676 Roo.tree.MultiSelectionModel = function(){
31677 this.selNodes = [];
31681 * @event selectionchange
31682 * Fires when the selected nodes change
31683 * @param {MultiSelectionModel} this
31684 * @param {Array} nodes Array of the selected nodes
31686 "selectionchange" : true
31688 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
31692 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31693 init : function(tree){
31695 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31696 tree.on("click", this.onNodeClick, this);
31699 onNodeClick : function(node, e){
31700 this.select(node, e, e.ctrlKey);
31705 * @param {TreeNode} node The node to select
31706 * @param {EventObject} e (optional) An event associated with the selection
31707 * @param {Boolean} keepExisting True to retain existing selections
31708 * @return {TreeNode} The selected node
31710 select : function(node, e, keepExisting){
31711 if(keepExisting !== true){
31712 this.clearSelections(true);
31714 if(this.isSelected(node)){
31715 this.lastSelNode = node;
31718 this.selNodes.push(node);
31719 this.selMap[node.id] = node;
31720 this.lastSelNode = node;
31721 node.ui.onSelectedChange(true);
31722 this.fireEvent("selectionchange", this, this.selNodes);
31728 * @param {TreeNode} node The node to unselect
31730 unselect : function(node){
31731 if(this.selMap[node.id]){
31732 node.ui.onSelectedChange(false);
31733 var sn = this.selNodes;
31736 index = sn.indexOf(node);
31738 for(var i = 0, len = sn.length; i < len; i++){
31746 this.selNodes.splice(index, 1);
31748 delete this.selMap[node.id];
31749 this.fireEvent("selectionchange", this, this.selNodes);
31754 * Clear all selections
31756 clearSelections : function(suppressEvent){
31757 var sn = this.selNodes;
31759 for(var i = 0, len = sn.length; i < len; i++){
31760 sn[i].ui.onSelectedChange(false);
31762 this.selNodes = [];
31764 if(suppressEvent !== true){
31765 this.fireEvent("selectionchange", this, this.selNodes);
31771 * Returns true if the node is selected
31772 * @param {TreeNode} node The node to check
31773 * @return {Boolean}
31775 isSelected : function(node){
31776 return this.selMap[node.id] ? true : false;
31780 * Returns an array of the selected nodes
31783 getSelectedNodes : function(){
31784 return this.selNodes;
31787 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31789 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31791 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31794 * Ext JS Library 1.1.1
31795 * Copyright(c) 2006-2007, Ext JS, LLC.
31797 * Originally Released Under LGPL - original licence link has changed is not relivant.
31800 * <script type="text/javascript">
31804 * @class Roo.tree.TreeNode
31805 * @extends Roo.data.Node
31806 * @cfg {String} text The text for this node
31807 * @cfg {Boolean} expanded true to start the node expanded
31808 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31809 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31810 * @cfg {Boolean} disabled true to start the node disabled
31811 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31812 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31813 * @cfg {String} cls A css class to be added to the node
31814 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31815 * @cfg {String} href URL of the link used for the node (defaults to #)
31816 * @cfg {String} hrefTarget target frame for the link
31817 * @cfg {String} qtip An Ext QuickTip for the node
31818 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31819 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31820 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31821 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31822 * (defaults to undefined with no checkbox rendered)
31824 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31826 Roo.tree.TreeNode = function(attributes){
31827 attributes = attributes || {};
31828 if(typeof attributes == "string"){
31829 attributes = {text: attributes};
31831 this.childrenRendered = false;
31832 this.rendered = false;
31833 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31834 this.expanded = attributes.expanded === true;
31835 this.isTarget = attributes.isTarget !== false;
31836 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31837 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31840 * Read-only. The text for this node. To change it use setText().
31843 this.text = attributes.text;
31845 * True if this node is disabled.
31848 this.disabled = attributes.disabled === true;
31852 * @event textchange
31853 * Fires when the text for this node is changed
31854 * @param {Node} this This node
31855 * @param {String} text The new text
31856 * @param {String} oldText The old text
31858 "textchange" : true,
31860 * @event beforeexpand
31861 * Fires before this node is expanded, return false to cancel.
31862 * @param {Node} this This node
31863 * @param {Boolean} deep
31864 * @param {Boolean} anim
31866 "beforeexpand" : true,
31868 * @event beforecollapse
31869 * Fires before this node is collapsed, return false to cancel.
31870 * @param {Node} this This node
31871 * @param {Boolean} deep
31872 * @param {Boolean} anim
31874 "beforecollapse" : true,
31877 * Fires when this node is expanded
31878 * @param {Node} this This node
31882 * @event disabledchange
31883 * Fires when the disabled status of this node changes
31884 * @param {Node} this This node
31885 * @param {Boolean} disabled
31887 "disabledchange" : true,
31890 * Fires when this node is collapsed
31891 * @param {Node} this This node
31895 * @event beforeclick
31896 * Fires before click processing. Return false to cancel the default action.
31897 * @param {Node} this This node
31898 * @param {Roo.EventObject} e The event object
31900 "beforeclick":true,
31902 * @event checkchange
31903 * Fires when a node with a checkbox's checked property changes
31904 * @param {Node} this This node
31905 * @param {Boolean} checked
31907 "checkchange":true,
31910 * Fires when this node is clicked
31911 * @param {Node} this This node
31912 * @param {Roo.EventObject} e The event object
31917 * Fires when this node is double clicked
31918 * @param {Node} this This node
31919 * @param {Roo.EventObject} e The event object
31923 * @event contextmenu
31924 * Fires when this node is right clicked
31925 * @param {Node} this This node
31926 * @param {Roo.EventObject} e The event object
31928 "contextmenu":true,
31930 * @event beforechildrenrendered
31931 * Fires right before the child nodes for this node are rendered
31932 * @param {Node} this This node
31934 "beforechildrenrendered":true
31937 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31940 * Read-only. The UI for this node
31943 this.ui = new uiClass(this);
31945 // finally support items[]
31946 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
31951 Roo.each(this.attributes.items, function(c) {
31952 this.appendChild(Roo.factory(c,Roo.Tree));
31954 delete this.attributes.items;
31959 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31960 preventHScroll: true,
31962 * Returns true if this node is expanded
31963 * @return {Boolean}
31965 isExpanded : function(){
31966 return this.expanded;
31970 * Returns the UI object for this node
31971 * @return {TreeNodeUI}
31973 getUI : function(){
31977 // private override
31978 setFirstChild : function(node){
31979 var of = this.firstChild;
31980 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31981 if(this.childrenRendered && of && node != of){
31982 of.renderIndent(true, true);
31985 this.renderIndent(true, true);
31989 // private override
31990 setLastChild : function(node){
31991 var ol = this.lastChild;
31992 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31993 if(this.childrenRendered && ol && node != ol){
31994 ol.renderIndent(true, true);
31997 this.renderIndent(true, true);
32001 // these methods are overridden to provide lazy rendering support
32002 // private override
32003 appendChild : function()
32005 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32006 if(node && this.childrenRendered){
32009 this.ui.updateExpandIcon();
32013 // private override
32014 removeChild : function(node){
32015 this.ownerTree.getSelectionModel().unselect(node);
32016 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32017 // if it's been rendered remove dom node
32018 if(this.childrenRendered){
32021 if(this.childNodes.length < 1){
32022 this.collapse(false, false);
32024 this.ui.updateExpandIcon();
32026 if(!this.firstChild) {
32027 this.childrenRendered = false;
32032 // private override
32033 insertBefore : function(node, refNode){
32034 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32035 if(newNode && refNode && this.childrenRendered){
32038 this.ui.updateExpandIcon();
32043 * Sets the text for this node
32044 * @param {String} text
32046 setText : function(text){
32047 var oldText = this.text;
32049 this.attributes.text = text;
32050 if(this.rendered){ // event without subscribing
32051 this.ui.onTextChange(this, text, oldText);
32053 this.fireEvent("textchange", this, text, oldText);
32057 * Triggers selection of this node
32059 select : function(){
32060 this.getOwnerTree().getSelectionModel().select(this);
32064 * Triggers deselection of this node
32066 unselect : function(){
32067 this.getOwnerTree().getSelectionModel().unselect(this);
32071 * Returns true if this node is selected
32072 * @return {Boolean}
32074 isSelected : function(){
32075 return this.getOwnerTree().getSelectionModel().isSelected(this);
32079 * Expand this node.
32080 * @param {Boolean} deep (optional) True to expand all children as well
32081 * @param {Boolean} anim (optional) false to cancel the default animation
32082 * @param {Function} callback (optional) A callback to be called when
32083 * expanding this node completes (does not wait for deep expand to complete).
32084 * Called with 1 parameter, this node.
32086 expand : function(deep, anim, callback){
32087 if(!this.expanded){
32088 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32091 if(!this.childrenRendered){
32092 this.renderChildren();
32094 this.expanded = true;
32095 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32096 this.ui.animExpand(function(){
32097 this.fireEvent("expand", this);
32098 if(typeof callback == "function"){
32102 this.expandChildNodes(true);
32104 }.createDelegate(this));
32108 this.fireEvent("expand", this);
32109 if(typeof callback == "function"){
32114 if(typeof callback == "function"){
32119 this.expandChildNodes(true);
32123 isHiddenRoot : function(){
32124 return this.isRoot && !this.getOwnerTree().rootVisible;
32128 * Collapse this node.
32129 * @param {Boolean} deep (optional) True to collapse all children as well
32130 * @param {Boolean} anim (optional) false to cancel the default animation
32132 collapse : function(deep, anim){
32133 if(this.expanded && !this.isHiddenRoot()){
32134 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32137 this.expanded = false;
32138 if((this.getOwnerTree().animate && anim !== false) || anim){
32139 this.ui.animCollapse(function(){
32140 this.fireEvent("collapse", this);
32142 this.collapseChildNodes(true);
32144 }.createDelegate(this));
32147 this.ui.collapse();
32148 this.fireEvent("collapse", this);
32152 var cs = this.childNodes;
32153 for(var i = 0, len = cs.length; i < len; i++) {
32154 cs[i].collapse(true, false);
32160 delayedExpand : function(delay){
32161 if(!this.expandProcId){
32162 this.expandProcId = this.expand.defer(delay, this);
32167 cancelExpand : function(){
32168 if(this.expandProcId){
32169 clearTimeout(this.expandProcId);
32171 this.expandProcId = false;
32175 * Toggles expanded/collapsed state of the node
32177 toggle : function(){
32186 * Ensures all parent nodes are expanded
32188 ensureVisible : function(callback){
32189 var tree = this.getOwnerTree();
32190 tree.expandPath(this.parentNode.getPath(), false, function(){
32191 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32192 Roo.callback(callback);
32193 }.createDelegate(this));
32197 * Expand all child nodes
32198 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32200 expandChildNodes : function(deep){
32201 var cs = this.childNodes;
32202 for(var i = 0, len = cs.length; i < len; i++) {
32203 cs[i].expand(deep);
32208 * Collapse all child nodes
32209 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32211 collapseChildNodes : function(deep){
32212 var cs = this.childNodes;
32213 for(var i = 0, len = cs.length; i < len; i++) {
32214 cs[i].collapse(deep);
32219 * Disables this node
32221 disable : function(){
32222 this.disabled = true;
32224 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32225 this.ui.onDisableChange(this, true);
32227 this.fireEvent("disabledchange", this, true);
32231 * Enables this node
32233 enable : function(){
32234 this.disabled = false;
32235 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32236 this.ui.onDisableChange(this, false);
32238 this.fireEvent("disabledchange", this, false);
32242 renderChildren : function(suppressEvent){
32243 if(suppressEvent !== false){
32244 this.fireEvent("beforechildrenrendered", this);
32246 var cs = this.childNodes;
32247 for(var i = 0, len = cs.length; i < len; i++){
32248 cs[i].render(true);
32250 this.childrenRendered = true;
32254 sort : function(fn, scope){
32255 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32256 if(this.childrenRendered){
32257 var cs = this.childNodes;
32258 for(var i = 0, len = cs.length; i < len; i++){
32259 cs[i].render(true);
32265 render : function(bulkRender){
32266 this.ui.render(bulkRender);
32267 if(!this.rendered){
32268 this.rendered = true;
32270 this.expanded = false;
32271 this.expand(false, false);
32277 renderIndent : function(deep, refresh){
32279 this.ui.childIndent = null;
32281 this.ui.renderIndent();
32282 if(deep === true && this.childrenRendered){
32283 var cs = this.childNodes;
32284 for(var i = 0, len = cs.length; i < len; i++){
32285 cs[i].renderIndent(true, refresh);
32291 * Ext JS Library 1.1.1
32292 * Copyright(c) 2006-2007, Ext JS, LLC.
32294 * Originally Released Under LGPL - original licence link has changed is not relivant.
32297 * <script type="text/javascript">
32301 * @class Roo.tree.AsyncTreeNode
32302 * @extends Roo.tree.TreeNode
32303 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32305 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32307 Roo.tree.AsyncTreeNode = function(config){
32308 this.loaded = false;
32309 this.loading = false;
32310 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32312 * @event beforeload
32313 * Fires before this node is loaded, return false to cancel
32314 * @param {Node} this This node
32316 this.addEvents({'beforeload':true, 'load': true});
32319 * Fires when this node is loaded
32320 * @param {Node} this This node
32323 * The loader used by this node (defaults to using the tree's defined loader)
32328 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32329 expand : function(deep, anim, callback){
32330 if(this.loading){ // if an async load is already running, waiting til it's done
32332 var f = function(){
32333 if(!this.loading){ // done loading
32334 clearInterval(timer);
32335 this.expand(deep, anim, callback);
32337 }.createDelegate(this);
32338 timer = setInterval(f, 200);
32342 if(this.fireEvent("beforeload", this) === false){
32345 this.loading = true;
32346 this.ui.beforeLoad(this);
32347 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32349 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32353 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32357 * Returns true if this node is currently loading
32358 * @return {Boolean}
32360 isLoading : function(){
32361 return this.loading;
32364 loadComplete : function(deep, anim, callback){
32365 this.loading = false;
32366 this.loaded = true;
32367 this.ui.afterLoad(this);
32368 this.fireEvent("load", this);
32369 this.expand(deep, anim, callback);
32373 * Returns true if this node has been loaded
32374 * @return {Boolean}
32376 isLoaded : function(){
32377 return this.loaded;
32380 hasChildNodes : function(){
32381 if(!this.isLeaf() && !this.loaded){
32384 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32389 * Trigger a reload for this node
32390 * @param {Function} callback
32392 reload : function(callback){
32393 this.collapse(false, false);
32394 while(this.firstChild){
32395 this.removeChild(this.firstChild);
32397 this.childrenRendered = false;
32398 this.loaded = false;
32399 if(this.isHiddenRoot()){
32400 this.expanded = false;
32402 this.expand(false, false, callback);
32406 * Ext JS Library 1.1.1
32407 * Copyright(c) 2006-2007, Ext JS, LLC.
32409 * Originally Released Under LGPL - original licence link has changed is not relivant.
32412 * <script type="text/javascript">
32416 * @class Roo.tree.TreeNodeUI
32418 * @param {Object} node The node to render
32419 * The TreeNode UI implementation is separate from the
32420 * tree implementation. Unless you are customizing the tree UI,
32421 * you should never have to use this directly.
32423 Roo.tree.TreeNodeUI = function(node){
32425 this.rendered = false;
32426 this.animating = false;
32427 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32430 Roo.tree.TreeNodeUI.prototype = {
32431 removeChild : function(node){
32433 this.ctNode.removeChild(node.ui.getEl());
32437 beforeLoad : function(){
32438 this.addClass("x-tree-node-loading");
32441 afterLoad : function(){
32442 this.removeClass("x-tree-node-loading");
32445 onTextChange : function(node, text, oldText){
32447 this.textNode.innerHTML = text;
32451 onDisableChange : function(node, state){
32452 this.disabled = state;
32454 this.addClass("x-tree-node-disabled");
32456 this.removeClass("x-tree-node-disabled");
32460 onSelectedChange : function(state){
32463 this.addClass("x-tree-selected");
32466 this.removeClass("x-tree-selected");
32470 onMove : function(tree, node, oldParent, newParent, index, refNode){
32471 this.childIndent = null;
32473 var targetNode = newParent.ui.getContainer();
32474 if(!targetNode){//target not rendered
32475 this.holder = document.createElement("div");
32476 this.holder.appendChild(this.wrap);
32479 var insertBefore = refNode ? refNode.ui.getEl() : null;
32481 targetNode.insertBefore(this.wrap, insertBefore);
32483 targetNode.appendChild(this.wrap);
32485 this.node.renderIndent(true);
32489 addClass : function(cls){
32491 Roo.fly(this.elNode).addClass(cls);
32495 removeClass : function(cls){
32497 Roo.fly(this.elNode).removeClass(cls);
32501 remove : function(){
32503 this.holder = document.createElement("div");
32504 this.holder.appendChild(this.wrap);
32508 fireEvent : function(){
32509 return this.node.fireEvent.apply(this.node, arguments);
32512 initEvents : function(){
32513 this.node.on("move", this.onMove, this);
32514 var E = Roo.EventManager;
32515 var a = this.anchor;
32517 var el = Roo.fly(a, '_treeui');
32519 if(Roo.isOpera){ // opera render bug ignores the CSS
32520 el.setStyle("text-decoration", "none");
32523 el.on("click", this.onClick, this);
32524 el.on("dblclick", this.onDblClick, this);
32527 Roo.EventManager.on(this.checkbox,
32528 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32531 el.on("contextmenu", this.onContextMenu, this);
32533 var icon = Roo.fly(this.iconNode);
32534 icon.on("click", this.onClick, this);
32535 icon.on("dblclick", this.onDblClick, this);
32536 icon.on("contextmenu", this.onContextMenu, this);
32537 E.on(this.ecNode, "click", this.ecClick, this, true);
32539 if(this.node.disabled){
32540 this.addClass("x-tree-node-disabled");
32542 if(this.node.hidden){
32543 this.addClass("x-tree-node-disabled");
32545 var ot = this.node.getOwnerTree();
32546 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32547 if(dd && (!this.node.isRoot || ot.rootVisible)){
32548 Roo.dd.Registry.register(this.elNode, {
32550 handles: this.getDDHandles(),
32556 getDDHandles : function(){
32557 return [this.iconNode, this.textNode];
32562 this.wrap.style.display = "none";
32568 this.wrap.style.display = "";
32572 onContextMenu : function(e){
32573 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32574 e.preventDefault();
32576 this.fireEvent("contextmenu", this.node, e);
32580 onClick : function(e){
32585 if(this.fireEvent("beforeclick", this.node, e) !== false){
32586 if(!this.disabled && this.node.attributes.href){
32587 this.fireEvent("click", this.node, e);
32590 e.preventDefault();
32595 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32596 this.node.toggle();
32599 this.fireEvent("click", this.node, e);
32605 onDblClick : function(e){
32606 e.preventDefault();
32611 this.toggleCheck();
32613 if(!this.animating && this.node.hasChildNodes()){
32614 this.node.toggle();
32616 this.fireEvent("dblclick", this.node, e);
32619 onCheckChange : function(){
32620 var checked = this.checkbox.checked;
32621 this.node.attributes.checked = checked;
32622 this.fireEvent('checkchange', this.node, checked);
32625 ecClick : function(e){
32626 if(!this.animating && this.node.hasChildNodes()){
32627 this.node.toggle();
32631 startDrop : function(){
32632 this.dropping = true;
32635 // delayed drop so the click event doesn't get fired on a drop
32636 endDrop : function(){
32637 setTimeout(function(){
32638 this.dropping = false;
32639 }.createDelegate(this), 50);
32642 expand : function(){
32643 this.updateExpandIcon();
32644 this.ctNode.style.display = "";
32647 focus : function(){
32648 if(!this.node.preventHScroll){
32649 try{this.anchor.focus();
32651 }else if(!Roo.isIE){
32653 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32654 var l = noscroll.scrollLeft;
32655 this.anchor.focus();
32656 noscroll.scrollLeft = l;
32661 toggleCheck : function(value){
32662 var cb = this.checkbox;
32664 cb.checked = (value === undefined ? !cb.checked : value);
32670 this.anchor.blur();
32674 animExpand : function(callback){
32675 var ct = Roo.get(this.ctNode);
32677 if(!this.node.hasChildNodes()){
32678 this.updateExpandIcon();
32679 this.ctNode.style.display = "";
32680 Roo.callback(callback);
32683 this.animating = true;
32684 this.updateExpandIcon();
32687 callback : function(){
32688 this.animating = false;
32689 Roo.callback(callback);
32692 duration: this.node.ownerTree.duration || .25
32696 highlight : function(){
32697 var tree = this.node.getOwnerTree();
32698 Roo.fly(this.wrap).highlight(
32699 tree.hlColor || "C3DAF9",
32700 {endColor: tree.hlBaseColor}
32704 collapse : function(){
32705 this.updateExpandIcon();
32706 this.ctNode.style.display = "none";
32709 animCollapse : function(callback){
32710 var ct = Roo.get(this.ctNode);
32711 ct.enableDisplayMode('block');
32714 this.animating = true;
32715 this.updateExpandIcon();
32718 callback : function(){
32719 this.animating = false;
32720 Roo.callback(callback);
32723 duration: this.node.ownerTree.duration || .25
32727 getContainer : function(){
32728 return this.ctNode;
32731 getEl : function(){
32735 appendDDGhost : function(ghostNode){
32736 ghostNode.appendChild(this.elNode.cloneNode(true));
32739 getDDRepairXY : function(){
32740 return Roo.lib.Dom.getXY(this.iconNode);
32743 onRender : function(){
32747 render : function(bulkRender){
32748 var n = this.node, a = n.attributes;
32749 var targetNode = n.parentNode ?
32750 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32752 if(!this.rendered){
32753 this.rendered = true;
32755 this.renderElements(n, a, targetNode, bulkRender);
32758 if(this.textNode.setAttributeNS){
32759 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32761 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32764 this.textNode.setAttribute("ext:qtip", a.qtip);
32766 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32769 }else if(a.qtipCfg){
32770 a.qtipCfg.target = Roo.id(this.textNode);
32771 Roo.QuickTips.register(a.qtipCfg);
32774 if(!this.node.expanded){
32775 this.updateExpandIcon();
32778 if(bulkRender === true) {
32779 targetNode.appendChild(this.wrap);
32784 renderElements : function(n, a, targetNode, bulkRender)
32786 // add some indent caching, this helps performance when rendering a large tree
32787 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32788 var t = n.getOwnerTree();
32789 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32790 if (typeof(n.attributes.html) != 'undefined') {
32791 txt = n.attributes.html;
32793 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32794 var cb = typeof a.checked == 'boolean';
32795 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32796 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32797 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32798 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32799 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32800 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32801 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32802 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32803 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32804 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32807 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32808 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32809 n.nextSibling.ui.getEl(), buf.join(""));
32811 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32814 this.elNode = this.wrap.childNodes[0];
32815 this.ctNode = this.wrap.childNodes[1];
32816 var cs = this.elNode.childNodes;
32817 this.indentNode = cs[0];
32818 this.ecNode = cs[1];
32819 this.iconNode = cs[2];
32822 this.checkbox = cs[3];
32825 this.anchor = cs[index];
32826 this.textNode = cs[index].firstChild;
32829 getAnchor : function(){
32830 return this.anchor;
32833 getTextEl : function(){
32834 return this.textNode;
32837 getIconEl : function(){
32838 return this.iconNode;
32841 isChecked : function(){
32842 return this.checkbox ? this.checkbox.checked : false;
32845 updateExpandIcon : function(){
32847 var n = this.node, c1, c2;
32848 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32849 var hasChild = n.hasChildNodes();
32853 c1 = "x-tree-node-collapsed";
32854 c2 = "x-tree-node-expanded";
32857 c1 = "x-tree-node-expanded";
32858 c2 = "x-tree-node-collapsed";
32861 this.removeClass("x-tree-node-leaf");
32862 this.wasLeaf = false;
32864 if(this.c1 != c1 || this.c2 != c2){
32865 Roo.fly(this.elNode).replaceClass(c1, c2);
32866 this.c1 = c1; this.c2 = c2;
32869 // this changes non-leafs into leafs if they have no children.
32870 // it's not very rational behaviour..
32872 if(!this.wasLeaf && this.node.leaf){
32873 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32876 this.wasLeaf = true;
32879 var ecc = "x-tree-ec-icon "+cls;
32880 if(this.ecc != ecc){
32881 this.ecNode.className = ecc;
32887 getChildIndent : function(){
32888 if(!this.childIndent){
32892 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32894 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32896 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32901 this.childIndent = buf.join("");
32903 return this.childIndent;
32906 renderIndent : function(){
32909 var p = this.node.parentNode;
32911 indent = p.ui.getChildIndent();
32913 if(this.indentMarkup != indent){ // don't rerender if not required
32914 this.indentNode.innerHTML = indent;
32915 this.indentMarkup = indent;
32917 this.updateExpandIcon();
32922 Roo.tree.RootTreeNodeUI = function(){
32923 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32925 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32926 render : function(){
32927 if(!this.rendered){
32928 var targetNode = this.node.ownerTree.innerCt.dom;
32929 this.node.expanded = true;
32930 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32931 this.wrap = this.ctNode = targetNode.firstChild;
32934 collapse : function(){
32936 expand : function(){
32940 * Ext JS Library 1.1.1
32941 * Copyright(c) 2006-2007, Ext JS, LLC.
32943 * Originally Released Under LGPL - original licence link has changed is not relivant.
32946 * <script type="text/javascript">
32949 * @class Roo.tree.TreeLoader
32950 * @extends Roo.util.Observable
32951 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32952 * nodes from a specified URL. The response must be a javascript Array definition
32953 * who's elements are node definition objects. eg:
32958 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
32959 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
32966 * The old style respose with just an array is still supported, but not recommended.
32969 * A server request is sent, and child nodes are loaded only when a node is expanded.
32970 * The loading node's id is passed to the server under the parameter name "node" to
32971 * enable the server to produce the correct child nodes.
32973 * To pass extra parameters, an event handler may be attached to the "beforeload"
32974 * event, and the parameters specified in the TreeLoader's baseParams property:
32976 myTreeLoader.on("beforeload", function(treeLoader, node) {
32977 this.baseParams.category = node.attributes.category;
32980 * This would pass an HTTP parameter called "category" to the server containing
32981 * the value of the Node's "category" attribute.
32983 * Creates a new Treeloader.
32984 * @param {Object} config A config object containing config properties.
32986 Roo.tree.TreeLoader = function(config){
32987 this.baseParams = {};
32988 this.requestMethod = "POST";
32989 Roo.apply(this, config);
32994 * @event beforeload
32995 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32996 * @param {Object} This TreeLoader object.
32997 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32998 * @param {Object} callback The callback function specified in the {@link #load} call.
33003 * Fires when the node has been successfuly loaded.
33004 * @param {Object} This TreeLoader object.
33005 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33006 * @param {Object} response The response object containing the data from the server.
33010 * @event loadexception
33011 * Fires if the network request failed.
33012 * @param {Object} This TreeLoader object.
33013 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33014 * @param {Object} response The response object containing the data from the server.
33016 loadexception : true,
33019 * Fires before a node is created, enabling you to return custom Node types
33020 * @param {Object} This TreeLoader object.
33021 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33026 Roo.tree.TreeLoader.superclass.constructor.call(this);
33029 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33031 * @cfg {String} dataUrl The URL from which to request a Json string which
33032 * specifies an array of node definition object representing the child nodes
33036 * @cfg {String} requestMethod either GET or POST
33037 * defaults to POST (due to BC)
33041 * @cfg {Object} baseParams (optional) An object containing properties which
33042 * specify HTTP parameters to be passed to each request for child nodes.
33045 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33046 * created by this loader. If the attributes sent by the server have an attribute in this object,
33047 * they take priority.
33050 * @cfg {Object} uiProviders (optional) An object containing properties which
33052 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33053 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33054 * <i>uiProvider</i> attribute of a returned child node is a string rather
33055 * than a reference to a TreeNodeUI implementation, this that string value
33056 * is used as a property name in the uiProviders object. You can define the provider named
33057 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33062 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33063 * child nodes before loading.
33065 clearOnLoad : true,
33068 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33069 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33070 * Grid query { data : [ .....] }
33075 * @cfg {String} queryParam (optional)
33076 * Name of the query as it will be passed on the querystring (defaults to 'node')
33077 * eg. the request will be ?node=[id]
33084 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33085 * This is called automatically when a node is expanded, but may be used to reload
33086 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33087 * @param {Roo.tree.TreeNode} node
33088 * @param {Function} callback
33090 load : function(node, callback){
33091 if(this.clearOnLoad){
33092 while(node.firstChild){
33093 node.removeChild(node.firstChild);
33096 if(node.attributes.children){ // preloaded json children
33097 var cs = node.attributes.children;
33098 for(var i = 0, len = cs.length; i < len; i++){
33099 node.appendChild(this.createNode(cs[i]));
33101 if(typeof callback == "function"){
33104 }else if(this.dataUrl){
33105 this.requestData(node, callback);
33109 getParams: function(node){
33110 var buf = [], bp = this.baseParams;
33111 for(var key in bp){
33112 if(typeof bp[key] != "function"){
33113 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33116 var n = this.queryParam === false ? 'node' : this.queryParam;
33117 buf.push(n + "=", encodeURIComponent(node.id));
33118 return buf.join("");
33121 requestData : function(node, callback){
33122 if(this.fireEvent("beforeload", this, node, callback) !== false){
33123 this.transId = Roo.Ajax.request({
33124 method:this.requestMethod,
33125 url: this.dataUrl||this.url,
33126 success: this.handleResponse,
33127 failure: this.handleFailure,
33129 argument: {callback: callback, node: node},
33130 params: this.getParams(node)
33133 // if the load is cancelled, make sure we notify
33134 // the node that we are done
33135 if(typeof callback == "function"){
33141 isLoading : function(){
33142 return this.transId ? true : false;
33145 abort : function(){
33146 if(this.isLoading()){
33147 Roo.Ajax.abort(this.transId);
33152 createNode : function(attr)
33154 // apply baseAttrs, nice idea Corey!
33155 if(this.baseAttrs){
33156 Roo.applyIf(attr, this.baseAttrs);
33158 if(this.applyLoader !== false){
33159 attr.loader = this;
33161 // uiProvider = depreciated..
33163 if(typeof(attr.uiProvider) == 'string'){
33164 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33165 /** eval:var:attr */ eval(attr.uiProvider);
33167 if(typeof(this.uiProviders['default']) != 'undefined') {
33168 attr.uiProvider = this.uiProviders['default'];
33171 this.fireEvent('create', this, attr);
33173 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33175 new Roo.tree.TreeNode(attr) :
33176 new Roo.tree.AsyncTreeNode(attr));
33179 processResponse : function(response, node, callback)
33181 var json = response.responseText;
33184 var o = Roo.decode(json);
33186 if (this.root === false && typeof(o.success) != undefined) {
33187 this.root = 'data'; // the default behaviour for list like data..
33190 if (this.root !== false && !o.success) {
33191 // it's a failure condition.
33192 var a = response.argument;
33193 this.fireEvent("loadexception", this, a.node, response);
33194 Roo.log("Load failed - should have a handler really");
33200 if (this.root !== false) {
33204 for(var i = 0, len = o.length; i < len; i++){
33205 var n = this.createNode(o[i]);
33207 node.appendChild(n);
33210 if(typeof callback == "function"){
33211 callback(this, node);
33214 this.handleFailure(response);
33218 handleResponse : function(response){
33219 this.transId = false;
33220 var a = response.argument;
33221 this.processResponse(response, a.node, a.callback);
33222 this.fireEvent("load", this, a.node, response);
33225 handleFailure : function(response)
33227 // should handle failure better..
33228 this.transId = false;
33229 var a = response.argument;
33230 this.fireEvent("loadexception", this, a.node, response);
33231 if(typeof a.callback == "function"){
33232 a.callback(this, a.node);
33237 * Ext JS Library 1.1.1
33238 * Copyright(c) 2006-2007, Ext JS, LLC.
33240 * Originally Released Under LGPL - original licence link has changed is not relivant.
33243 * <script type="text/javascript">
33247 * @class Roo.tree.TreeFilter
33248 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33249 * @param {TreePanel} tree
33250 * @param {Object} config (optional)
33252 Roo.tree.TreeFilter = function(tree, config){
33254 this.filtered = {};
33255 Roo.apply(this, config);
33258 Roo.tree.TreeFilter.prototype = {
33265 * Filter the data by a specific attribute.
33266 * @param {String/RegExp} value Either string that the attribute value
33267 * should start with or a RegExp to test against the attribute
33268 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33269 * @param {TreeNode} startNode (optional) The node to start the filter at.
33271 filter : function(value, attr, startNode){
33272 attr = attr || "text";
33274 if(typeof value == "string"){
33275 var vlen = value.length;
33276 // auto clear empty filter
33277 if(vlen == 0 && this.clearBlank){
33281 value = value.toLowerCase();
33283 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33285 }else if(value.exec){ // regex?
33287 return value.test(n.attributes[attr]);
33290 throw 'Illegal filter type, must be string or regex';
33292 this.filterBy(f, null, startNode);
33296 * Filter by a function. The passed function will be called with each
33297 * node in the tree (or from the startNode). If the function returns true, the node is kept
33298 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33299 * @param {Function} fn The filter function
33300 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33302 filterBy : function(fn, scope, startNode){
33303 startNode = startNode || this.tree.root;
33304 if(this.autoClear){
33307 var af = this.filtered, rv = this.reverse;
33308 var f = function(n){
33309 if(n == startNode){
33315 var m = fn.call(scope || n, n);
33323 startNode.cascade(f);
33326 if(typeof id != "function"){
33328 if(n && n.parentNode){
33329 n.parentNode.removeChild(n);
33337 * Clears the current filter. Note: with the "remove" option
33338 * set a filter cannot be cleared.
33340 clear : function(){
33342 var af = this.filtered;
33344 if(typeof id != "function"){
33351 this.filtered = {};
33356 * Ext JS Library 1.1.1
33357 * Copyright(c) 2006-2007, Ext JS, LLC.
33359 * Originally Released Under LGPL - original licence link has changed is not relivant.
33362 * <script type="text/javascript">
33367 * @class Roo.tree.TreeSorter
33368 * Provides sorting of nodes in a TreePanel
33370 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33371 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33372 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33373 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33374 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33375 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33377 * @param {TreePanel} tree
33378 * @param {Object} config
33380 Roo.tree.TreeSorter = function(tree, config){
33381 Roo.apply(this, config);
33382 tree.on("beforechildrenrendered", this.doSort, this);
33383 tree.on("append", this.updateSort, this);
33384 tree.on("insert", this.updateSort, this);
33386 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33387 var p = this.property || "text";
33388 var sortType = this.sortType;
33389 var fs = this.folderSort;
33390 var cs = this.caseSensitive === true;
33391 var leafAttr = this.leafAttr || 'leaf';
33393 this.sortFn = function(n1, n2){
33395 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33398 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33402 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33403 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33405 return dsc ? +1 : -1;
33407 return dsc ? -1 : +1;
33414 Roo.tree.TreeSorter.prototype = {
33415 doSort : function(node){
33416 node.sort(this.sortFn);
33419 compareNodes : function(n1, n2){
33420 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33423 updateSort : function(tree, node){
33424 if(node.childrenRendered){
33425 this.doSort.defer(1, this, [node]);
33430 * Ext JS Library 1.1.1
33431 * Copyright(c) 2006-2007, Ext JS, LLC.
33433 * Originally Released Under LGPL - original licence link has changed is not relivant.
33436 * <script type="text/javascript">
33439 if(Roo.dd.DropZone){
33441 Roo.tree.TreeDropZone = function(tree, config){
33442 this.allowParentInsert = false;
33443 this.allowContainerDrop = false;
33444 this.appendOnly = false;
33445 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33447 this.lastInsertClass = "x-tree-no-status";
33448 this.dragOverData = {};
33451 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33452 ddGroup : "TreeDD",
33454 expandDelay : 1000,
33456 expandNode : function(node){
33457 if(node.hasChildNodes() && !node.isExpanded()){
33458 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33462 queueExpand : function(node){
33463 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33466 cancelExpand : function(){
33467 if(this.expandProcId){
33468 clearTimeout(this.expandProcId);
33469 this.expandProcId = false;
33473 isValidDropPoint : function(n, pt, dd, e, data){
33474 if(!n || !data){ return false; }
33475 var targetNode = n.node;
33476 var dropNode = data.node;
33477 // default drop rules
33478 if(!(targetNode && targetNode.isTarget && pt)){
33481 if(pt == "append" && targetNode.allowChildren === false){
33484 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33487 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33490 // reuse the object
33491 var overEvent = this.dragOverData;
33492 overEvent.tree = this.tree;
33493 overEvent.target = targetNode;
33494 overEvent.data = data;
33495 overEvent.point = pt;
33496 overEvent.source = dd;
33497 overEvent.rawEvent = e;
33498 overEvent.dropNode = dropNode;
33499 overEvent.cancel = false;
33500 var result = this.tree.fireEvent("nodedragover", overEvent);
33501 return overEvent.cancel === false && result !== false;
33504 getDropPoint : function(e, n, dd){
33507 return tn.allowChildren !== false ? "append" : false; // always append for root
33509 var dragEl = n.ddel;
33510 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33511 var y = Roo.lib.Event.getPageY(e);
33512 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33514 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33515 var noAppend = tn.allowChildren === false;
33516 if(this.appendOnly || tn.parentNode.allowChildren === false){
33517 return noAppend ? false : "append";
33519 var noBelow = false;
33520 if(!this.allowParentInsert){
33521 noBelow = tn.hasChildNodes() && tn.isExpanded();
33523 var q = (b - t) / (noAppend ? 2 : 3);
33524 if(y >= t && y < (t + q)){
33526 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33533 onNodeEnter : function(n, dd, e, data){
33534 this.cancelExpand();
33537 onNodeOver : function(n, dd, e, data){
33538 var pt = this.getDropPoint(e, n, dd);
33541 // auto node expand check
33542 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33543 this.queueExpand(node);
33544 }else if(pt != "append"){
33545 this.cancelExpand();
33548 // set the insert point style on the target node
33549 var returnCls = this.dropNotAllowed;
33550 if(this.isValidDropPoint(n, pt, dd, e, data)){
33555 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33556 cls = "x-tree-drag-insert-above";
33557 }else if(pt == "below"){
33558 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33559 cls = "x-tree-drag-insert-below";
33561 returnCls = "x-tree-drop-ok-append";
33562 cls = "x-tree-drag-append";
33564 if(this.lastInsertClass != cls){
33565 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33566 this.lastInsertClass = cls;
33573 onNodeOut : function(n, dd, e, data){
33574 this.cancelExpand();
33575 this.removeDropIndicators(n);
33578 onNodeDrop : function(n, dd, e, data){
33579 var point = this.getDropPoint(e, n, dd);
33580 var targetNode = n.node;
33581 targetNode.ui.startDrop();
33582 if(!this.isValidDropPoint(n, point, dd, e, data)){
33583 targetNode.ui.endDrop();
33586 // first try to find the drop node
33587 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33590 target: targetNode,
33595 dropNode: dropNode,
33598 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33599 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33600 targetNode.ui.endDrop();
33603 // allow target changing
33604 targetNode = dropEvent.target;
33605 if(point == "append" && !targetNode.isExpanded()){
33606 targetNode.expand(false, null, function(){
33607 this.completeDrop(dropEvent);
33608 }.createDelegate(this));
33610 this.completeDrop(dropEvent);
33615 completeDrop : function(de){
33616 var ns = de.dropNode, p = de.point, t = de.target;
33617 if(!(ns instanceof Array)){
33621 for(var i = 0, len = ns.length; i < len; i++){
33624 t.parentNode.insertBefore(n, t);
33625 }else if(p == "below"){
33626 t.parentNode.insertBefore(n, t.nextSibling);
33632 if(this.tree.hlDrop){
33636 this.tree.fireEvent("nodedrop", de);
33639 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33640 if(this.tree.hlDrop){
33641 dropNode.ui.focus();
33642 dropNode.ui.highlight();
33644 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33647 getTree : function(){
33651 removeDropIndicators : function(n){
33654 Roo.fly(el).removeClass([
33655 "x-tree-drag-insert-above",
33656 "x-tree-drag-insert-below",
33657 "x-tree-drag-append"]);
33658 this.lastInsertClass = "_noclass";
33662 beforeDragDrop : function(target, e, id){
33663 this.cancelExpand();
33667 afterRepair : function(data){
33668 if(data && Roo.enableFx){
33669 data.node.ui.highlight();
33678 * Ext JS Library 1.1.1
33679 * Copyright(c) 2006-2007, Ext JS, LLC.
33681 * Originally Released Under LGPL - original licence link has changed is not relivant.
33684 * <script type="text/javascript">
33688 if(Roo.dd.DragZone){
33689 Roo.tree.TreeDragZone = function(tree, config){
33690 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33694 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33695 ddGroup : "TreeDD",
33697 onBeforeDrag : function(data, e){
33699 return n && n.draggable && !n.disabled;
33702 onInitDrag : function(e){
33703 var data = this.dragData;
33704 this.tree.getSelectionModel().select(data.node);
33705 this.proxy.update("");
33706 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33707 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33710 getRepairXY : function(e, data){
33711 return data.node.ui.getDDRepairXY();
33714 onEndDrag : function(data, e){
33715 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33718 onValidDrop : function(dd, e, id){
33719 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33723 beforeInvalidDrop : function(e, id){
33724 // this scrolls the original position back into view
33725 var sm = this.tree.getSelectionModel();
33726 sm.clearSelections();
33727 sm.select(this.dragData.node);
33732 * Ext JS Library 1.1.1
33733 * Copyright(c) 2006-2007, Ext JS, LLC.
33735 * Originally Released Under LGPL - original licence link has changed is not relivant.
33738 * <script type="text/javascript">
33741 * @class Roo.tree.TreeEditor
33742 * @extends Roo.Editor
33743 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33744 * as the editor field.
33746 * @param {Object} config (used to be the tree panel.)
33747 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33749 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
33750 * @cfg {Roo.form.TextField|Object} field The field configuration
33754 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
33757 if (oldconfig) { // old style..
33758 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
33761 tree = config.tree;
33762 config.field = config.field || {};
33763 config.field.xtype = 'TextField';
33764 field = Roo.factory(config.field, Roo.form);
33766 config = config || {};
33771 * @event beforenodeedit
33772 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
33773 * false from the handler of this event.
33774 * @param {Editor} this
33775 * @param {Roo.tree.Node} node
33777 "beforenodeedit" : true
33781 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
33785 tree.on('beforeclick', this.beforeNodeClick, this);
33786 tree.getTreeEl().on('mousedown', this.hide, this);
33787 this.on('complete', this.updateNode, this);
33788 this.on('beforestartedit', this.fitToTree, this);
33789 this.on('startedit', this.bindScroll, this, {delay:10});
33790 this.on('specialkey', this.onSpecialKey, this);
33793 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33795 * @cfg {String} alignment
33796 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33802 * @cfg {Boolean} hideEl
33803 * True to hide the bound element while the editor is displayed (defaults to false)
33807 * @cfg {String} cls
33808 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33810 cls: "x-small-editor x-tree-editor",
33812 * @cfg {Boolean} shim
33813 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33819 * @cfg {Number} maxWidth
33820 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33821 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33822 * scroll and client offsets into account prior to each edit.
33829 fitToTree : function(ed, el){
33830 var td = this.tree.getTreeEl().dom, nd = el.dom;
33831 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33832 td.scrollLeft = nd.offsetLeft;
33836 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33837 this.setSize(w, '');
33839 return this.fireEvent('beforenodeedit', this, this.editNode);
33844 triggerEdit : function(node){
33845 this.completeEdit();
33846 this.editNode = node;
33847 this.startEdit(node.ui.textNode, node.text);
33851 bindScroll : function(){
33852 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33856 beforeNodeClick : function(node, e){
33857 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33858 this.lastClick = new Date();
33859 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33861 this.triggerEdit(node);
33868 updateNode : function(ed, value){
33869 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33870 this.editNode.setText(value);
33874 onHide : function(){
33875 Roo.tree.TreeEditor.superclass.onHide.call(this);
33877 this.editNode.ui.focus();
33882 onSpecialKey : function(field, e){
33883 var k = e.getKey();
33887 }else if(k == e.ENTER && !e.hasModifier()){
33889 this.completeEdit();
33892 });//<Script type="text/javascript">
33895 * Ext JS Library 1.1.1
33896 * Copyright(c) 2006-2007, Ext JS, LLC.
33898 * Originally Released Under LGPL - original licence link has changed is not relivant.
33901 * <script type="text/javascript">
33905 * Not documented??? - probably should be...
33908 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33909 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33911 renderElements : function(n, a, targetNode, bulkRender){
33912 //consel.log("renderElements?");
33913 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33915 var t = n.getOwnerTree();
33916 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33918 var cols = t.columns;
33919 var bw = t.borderWidth;
33921 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33922 var cb = typeof a.checked == "boolean";
33923 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33924 var colcls = 'x-t-' + tid + '-c0';
33926 '<li class="x-tree-node">',
33929 '<div class="x-tree-node-el ', a.cls,'">',
33931 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33934 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33935 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33936 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33937 (a.icon ? ' x-tree-node-inline-icon' : ''),
33938 (a.iconCls ? ' '+a.iconCls : ''),
33939 '" unselectable="on" />',
33940 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33941 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33943 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33944 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33945 '<span unselectable="on" qtip="' + tx + '">',
33949 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33950 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33952 for(var i = 1, len = cols.length; i < len; i++){
33954 colcls = 'x-t-' + tid + '-c' +i;
33955 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33956 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33957 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33963 '<div class="x-clear"></div></div>',
33964 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33967 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33968 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33969 n.nextSibling.ui.getEl(), buf.join(""));
33971 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33973 var el = this.wrap.firstChild;
33975 this.elNode = el.firstChild;
33976 this.ranchor = el.childNodes[1];
33977 this.ctNode = this.wrap.childNodes[1];
33978 var cs = el.firstChild.childNodes;
33979 this.indentNode = cs[0];
33980 this.ecNode = cs[1];
33981 this.iconNode = cs[2];
33984 this.checkbox = cs[3];
33987 this.anchor = cs[index];
33989 this.textNode = cs[index].firstChild;
33991 //el.on("click", this.onClick, this);
33992 //el.on("dblclick", this.onDblClick, this);
33995 // console.log(this);
33997 initEvents : function(){
33998 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34001 var a = this.ranchor;
34003 var el = Roo.get(a);
34005 if(Roo.isOpera){ // opera render bug ignores the CSS
34006 el.setStyle("text-decoration", "none");
34009 el.on("click", this.onClick, this);
34010 el.on("dblclick", this.onDblClick, this);
34011 el.on("contextmenu", this.onContextMenu, this);
34015 /*onSelectedChange : function(state){
34018 this.addClass("x-tree-selected");
34021 this.removeClass("x-tree-selected");
34024 addClass : function(cls){
34026 Roo.fly(this.elRow).addClass(cls);
34032 removeClass : function(cls){
34034 Roo.fly(this.elRow).removeClass(cls);
34040 });//<Script type="text/javascript">
34044 * Ext JS Library 1.1.1
34045 * Copyright(c) 2006-2007, Ext JS, LLC.
34047 * Originally Released Under LGPL - original licence link has changed is not relivant.
34050 * <script type="text/javascript">
34055 * @class Roo.tree.ColumnTree
34056 * @extends Roo.data.TreePanel
34057 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34058 * @cfg {int} borderWidth compined right/left border allowance
34060 * @param {String/HTMLElement/Element} el The container element
34061 * @param {Object} config
34063 Roo.tree.ColumnTree = function(el, config)
34065 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34069 * Fire this event on a container when it resizes
34070 * @param {int} w Width
34071 * @param {int} h Height
34075 this.on('resize', this.onResize, this);
34078 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34082 borderWidth: Roo.isBorderBox ? 0 : 2,
34085 render : function(){
34086 // add the header.....
34088 Roo.tree.ColumnTree.superclass.render.apply(this);
34090 this.el.addClass('x-column-tree');
34092 this.headers = this.el.createChild(
34093 {cls:'x-tree-headers'},this.innerCt.dom);
34095 var cols = this.columns, c;
34096 var totalWidth = 0;
34098 var len = cols.length;
34099 for(var i = 0; i < len; i++){
34101 totalWidth += c.width;
34102 this.headEls.push(this.headers.createChild({
34103 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34105 cls:'x-tree-hd-text',
34108 style:'width:'+(c.width-this.borderWidth)+'px;'
34111 this.headers.createChild({cls:'x-clear'});
34112 // prevent floats from wrapping when clipped
34113 this.headers.setWidth(totalWidth);
34114 //this.innerCt.setWidth(totalWidth);
34115 this.innerCt.setStyle({ overflow: 'auto' });
34116 this.onResize(this.width, this.height);
34120 onResize : function(w,h)
34125 this.innerCt.setWidth(this.width);
34126 this.innerCt.setHeight(this.height-20);
34129 var cols = this.columns, c;
34130 var totalWidth = 0;
34132 var len = cols.length;
34133 for(var i = 0; i < len; i++){
34135 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34136 // it's the expander..
34137 expEl = this.headEls[i];
34140 totalWidth += c.width;
34144 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34146 this.headers.setWidth(w-20);
34155 * Ext JS Library 1.1.1
34156 * Copyright(c) 2006-2007, Ext JS, LLC.
34158 * Originally Released Under LGPL - original licence link has changed is not relivant.
34161 * <script type="text/javascript">
34165 * @class Roo.menu.Menu
34166 * @extends Roo.util.Observable
34167 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34168 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34170 * Creates a new Menu
34171 * @param {Object} config Configuration options
34173 Roo.menu.Menu = function(config){
34174 Roo.apply(this, config);
34175 this.id = this.id || Roo.id();
34178 * @event beforeshow
34179 * Fires before this menu is displayed
34180 * @param {Roo.menu.Menu} this
34184 * @event beforehide
34185 * Fires before this menu is hidden
34186 * @param {Roo.menu.Menu} this
34191 * Fires after this menu is displayed
34192 * @param {Roo.menu.Menu} this
34197 * Fires after this menu is hidden
34198 * @param {Roo.menu.Menu} this
34203 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34204 * @param {Roo.menu.Menu} this
34205 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34206 * @param {Roo.EventObject} e
34211 * Fires when the mouse is hovering over this menu
34212 * @param {Roo.menu.Menu} this
34213 * @param {Roo.EventObject} e
34214 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34219 * Fires when the mouse exits this menu
34220 * @param {Roo.menu.Menu} this
34221 * @param {Roo.EventObject} e
34222 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34227 * Fires when a menu item contained in this menu is clicked
34228 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34229 * @param {Roo.EventObject} e
34233 if (this.registerMenu) {
34234 Roo.menu.MenuMgr.register(this);
34237 var mis = this.items;
34238 this.items = new Roo.util.MixedCollection();
34240 this.add.apply(this, mis);
34244 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34246 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34250 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34251 * for bottom-right shadow (defaults to "sides")
34255 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34256 * this menu (defaults to "tl-tr?")
34258 subMenuAlign : "tl-tr?",
34260 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34261 * relative to its element of origin (defaults to "tl-bl?")
34263 defaultAlign : "tl-bl?",
34265 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34267 allowOtherMenus : false,
34269 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34271 registerMenu : true,
34276 render : function(){
34280 var el = this.el = new Roo.Layer({
34282 shadow:this.shadow,
34284 parentEl: this.parentEl || document.body,
34288 this.keyNav = new Roo.menu.MenuNav(this);
34291 el.addClass("x-menu-plain");
34294 el.addClass(this.cls);
34296 // generic focus element
34297 this.focusEl = el.createChild({
34298 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34300 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34301 ul.on("click", this.onClick, this);
34302 ul.on("mouseover", this.onMouseOver, this);
34303 ul.on("mouseout", this.onMouseOut, this);
34304 this.items.each(function(item){
34305 var li = document.createElement("li");
34306 li.className = "x-menu-list-item";
34307 ul.dom.appendChild(li);
34308 item.render(li, this);
34315 autoWidth : function(){
34316 var el = this.el, ul = this.ul;
34320 var w = this.width;
34323 }else if(Roo.isIE){
34324 el.setWidth(this.minWidth);
34325 var t = el.dom.offsetWidth; // force recalc
34326 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34331 delayAutoWidth : function(){
34334 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34336 this.awTask.delay(20);
34341 findTargetItem : function(e){
34342 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34343 if(t && t.menuItemId){
34344 return this.items.get(t.menuItemId);
34349 onClick : function(e){
34351 if(t = this.findTargetItem(e)){
34353 this.fireEvent("click", this, t, e);
34358 setActiveItem : function(item, autoExpand){
34359 if(item != this.activeItem){
34360 if(this.activeItem){
34361 this.activeItem.deactivate();
34363 this.activeItem = item;
34364 item.activate(autoExpand);
34365 }else if(autoExpand){
34371 tryActivate : function(start, step){
34372 var items = this.items;
34373 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34374 var item = items.get(i);
34375 if(!item.disabled && item.canActivate){
34376 this.setActiveItem(item, false);
34384 onMouseOver : function(e){
34386 if(t = this.findTargetItem(e)){
34387 if(t.canActivate && !t.disabled){
34388 this.setActiveItem(t, true);
34391 this.fireEvent("mouseover", this, e, t);
34395 onMouseOut : function(e){
34397 if(t = this.findTargetItem(e)){
34398 if(t == this.activeItem && t.shouldDeactivate(e)){
34399 this.activeItem.deactivate();
34400 delete this.activeItem;
34403 this.fireEvent("mouseout", this, e, t);
34407 * Read-only. Returns true if the menu is currently displayed, else false.
34410 isVisible : function(){
34411 return this.el && !this.hidden;
34415 * Displays this menu relative to another element
34416 * @param {String/HTMLElement/Roo.Element} element The element to align to
34417 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34418 * the element (defaults to this.defaultAlign)
34419 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34421 show : function(el, pos, parentMenu){
34422 this.parentMenu = parentMenu;
34426 this.fireEvent("beforeshow", this);
34427 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34431 * Displays this menu at a specific xy position
34432 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34433 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34435 showAt : function(xy, parentMenu, /* private: */_e){
34436 this.parentMenu = parentMenu;
34441 this.fireEvent("beforeshow", this);
34442 xy = this.el.adjustForConstraints(xy);
34446 this.hidden = false;
34448 this.fireEvent("show", this);
34451 focus : function(){
34453 this.doFocus.defer(50, this);
34457 doFocus : function(){
34459 this.focusEl.focus();
34464 * Hides this menu and optionally all parent menus
34465 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34467 hide : function(deep){
34468 if(this.el && this.isVisible()){
34469 this.fireEvent("beforehide", this);
34470 if(this.activeItem){
34471 this.activeItem.deactivate();
34472 this.activeItem = null;
34475 this.hidden = true;
34476 this.fireEvent("hide", this);
34478 if(deep === true && this.parentMenu){
34479 this.parentMenu.hide(true);
34484 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34485 * Any of the following are valid:
34487 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34488 * <li>An HTMLElement object which will be converted to a menu item</li>
34489 * <li>A menu item config object that will be created as a new menu item</li>
34490 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34491 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34496 var menu = new Roo.menu.Menu();
34498 // Create a menu item to add by reference
34499 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34501 // Add a bunch of items at once using different methods.
34502 // Only the last item added will be returned.
34503 var item = menu.add(
34504 menuItem, // add existing item by ref
34505 'Dynamic Item', // new TextItem
34506 '-', // new separator
34507 { text: 'Config Item' } // new item by config
34510 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34511 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34514 var a = arguments, l = a.length, item;
34515 for(var i = 0; i < l; i++){
34517 if ((typeof(el) == "object") && el.xtype && el.xns) {
34518 el = Roo.factory(el, Roo.menu);
34521 if(el.render){ // some kind of Item
34522 item = this.addItem(el);
34523 }else if(typeof el == "string"){ // string
34524 if(el == "separator" || el == "-"){
34525 item = this.addSeparator();
34527 item = this.addText(el);
34529 }else if(el.tagName || el.el){ // element
34530 item = this.addElement(el);
34531 }else if(typeof el == "object"){ // must be menu item config?
34532 item = this.addMenuItem(el);
34539 * Returns this menu's underlying {@link Roo.Element} object
34540 * @return {Roo.Element} The element
34542 getEl : function(){
34550 * Adds a separator bar to the menu
34551 * @return {Roo.menu.Item} The menu item that was added
34553 addSeparator : function(){
34554 return this.addItem(new Roo.menu.Separator());
34558 * Adds an {@link Roo.Element} object to the menu
34559 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34560 * @return {Roo.menu.Item} The menu item that was added
34562 addElement : function(el){
34563 return this.addItem(new Roo.menu.BaseItem(el));
34567 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34568 * @param {Roo.menu.Item} item The menu item to add
34569 * @return {Roo.menu.Item} The menu item that was added
34571 addItem : function(item){
34572 this.items.add(item);
34574 var li = document.createElement("li");
34575 li.className = "x-menu-list-item";
34576 this.ul.dom.appendChild(li);
34577 item.render(li, this);
34578 this.delayAutoWidth();
34584 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34585 * @param {Object} config A MenuItem config object
34586 * @return {Roo.menu.Item} The menu item that was added
34588 addMenuItem : function(config){
34589 if(!(config instanceof Roo.menu.Item)){
34590 if(typeof config.checked == "boolean"){ // must be check menu item config?
34591 config = new Roo.menu.CheckItem(config);
34593 config = new Roo.menu.Item(config);
34596 return this.addItem(config);
34600 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34601 * @param {String} text The text to display in the menu item
34602 * @return {Roo.menu.Item} The menu item that was added
34604 addText : function(text){
34605 return this.addItem(new Roo.menu.TextItem({ text : text }));
34609 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34610 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34611 * @param {Roo.menu.Item} item The menu item to add
34612 * @return {Roo.menu.Item} The menu item that was added
34614 insert : function(index, item){
34615 this.items.insert(index, item);
34617 var li = document.createElement("li");
34618 li.className = "x-menu-list-item";
34619 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34620 item.render(li, this);
34621 this.delayAutoWidth();
34627 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34628 * @param {Roo.menu.Item} item The menu item to remove
34630 remove : function(item){
34631 this.items.removeKey(item.id);
34636 * Removes and destroys all items in the menu
34638 removeAll : function(){
34640 while(f = this.items.first()){
34646 // MenuNav is a private utility class used internally by the Menu
34647 Roo.menu.MenuNav = function(menu){
34648 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34649 this.scope = this.menu = menu;
34652 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34653 doRelay : function(e, h){
34654 var k = e.getKey();
34655 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34656 this.menu.tryActivate(0, 1);
34659 return h.call(this.scope || this, e, this.menu);
34662 up : function(e, m){
34663 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34664 m.tryActivate(m.items.length-1, -1);
34668 down : function(e, m){
34669 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34670 m.tryActivate(0, 1);
34674 right : function(e, m){
34676 m.activeItem.expandMenu(true);
34680 left : function(e, m){
34682 if(m.parentMenu && m.parentMenu.activeItem){
34683 m.parentMenu.activeItem.activate();
34687 enter : function(e, m){
34689 e.stopPropagation();
34690 m.activeItem.onClick(e);
34691 m.fireEvent("click", this, m.activeItem);
34697 * Ext JS Library 1.1.1
34698 * Copyright(c) 2006-2007, Ext JS, LLC.
34700 * Originally Released Under LGPL - original licence link has changed is not relivant.
34703 * <script type="text/javascript">
34707 * @class Roo.menu.MenuMgr
34708 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34711 Roo.menu.MenuMgr = function(){
34712 var menus, active, groups = {}, attached = false, lastShow = new Date();
34714 // private - called when first menu is created
34717 active = new Roo.util.MixedCollection();
34718 Roo.get(document).addKeyListener(27, function(){
34719 if(active.length > 0){
34726 function hideAll(){
34727 if(active && active.length > 0){
34728 var c = active.clone();
34729 c.each(function(m){
34736 function onHide(m){
34738 if(active.length < 1){
34739 Roo.get(document).un("mousedown", onMouseDown);
34745 function onShow(m){
34746 var last = active.last();
34747 lastShow = new Date();
34750 Roo.get(document).on("mousedown", onMouseDown);
34754 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34755 m.parentMenu.activeChild = m;
34756 }else if(last && last.isVisible()){
34757 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34762 function onBeforeHide(m){
34764 m.activeChild.hide();
34766 if(m.autoHideTimer){
34767 clearTimeout(m.autoHideTimer);
34768 delete m.autoHideTimer;
34773 function onBeforeShow(m){
34774 var pm = m.parentMenu;
34775 if(!pm && !m.allowOtherMenus){
34777 }else if(pm && pm.activeChild && active != m){
34778 pm.activeChild.hide();
34783 function onMouseDown(e){
34784 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34790 function onBeforeCheck(mi, state){
34792 var g = groups[mi.group];
34793 for(var i = 0, l = g.length; i < l; i++){
34795 g[i].setChecked(false);
34804 * Hides all menus that are currently visible
34806 hideAll : function(){
34811 register : function(menu){
34815 menus[menu.id] = menu;
34816 menu.on("beforehide", onBeforeHide);
34817 menu.on("hide", onHide);
34818 menu.on("beforeshow", onBeforeShow);
34819 menu.on("show", onShow);
34820 var g = menu.group;
34821 if(g && menu.events["checkchange"]){
34825 groups[g].push(menu);
34826 menu.on("checkchange", onCheck);
34831 * Returns a {@link Roo.menu.Menu} object
34832 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34833 * be used to generate and return a new Menu instance.
34835 get : function(menu){
34836 if(typeof menu == "string"){ // menu id
34837 return menus[menu];
34838 }else if(menu.events){ // menu instance
34840 }else if(typeof menu.length == 'number'){ // array of menu items?
34841 return new Roo.menu.Menu({items:menu});
34842 }else{ // otherwise, must be a config
34843 return new Roo.menu.Menu(menu);
34848 unregister : function(menu){
34849 delete menus[menu.id];
34850 menu.un("beforehide", onBeforeHide);
34851 menu.un("hide", onHide);
34852 menu.un("beforeshow", onBeforeShow);
34853 menu.un("show", onShow);
34854 var g = menu.group;
34855 if(g && menu.events["checkchange"]){
34856 groups[g].remove(menu);
34857 menu.un("checkchange", onCheck);
34862 registerCheckable : function(menuItem){
34863 var g = menuItem.group;
34868 groups[g].push(menuItem);
34869 menuItem.on("beforecheckchange", onBeforeCheck);
34874 unregisterCheckable : function(menuItem){
34875 var g = menuItem.group;
34877 groups[g].remove(menuItem);
34878 menuItem.un("beforecheckchange", onBeforeCheck);
34884 * Ext JS Library 1.1.1
34885 * Copyright(c) 2006-2007, Ext JS, LLC.
34887 * Originally Released Under LGPL - original licence link has changed is not relivant.
34890 * <script type="text/javascript">
34895 * @class Roo.menu.BaseItem
34896 * @extends Roo.Component
34897 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34898 * management and base configuration options shared by all menu components.
34900 * Creates a new BaseItem
34901 * @param {Object} config Configuration options
34903 Roo.menu.BaseItem = function(config){
34904 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34909 * Fires when this item is clicked
34910 * @param {Roo.menu.BaseItem} this
34911 * @param {Roo.EventObject} e
34916 * Fires when this item is activated
34917 * @param {Roo.menu.BaseItem} this
34921 * @event deactivate
34922 * Fires when this item is deactivated
34923 * @param {Roo.menu.BaseItem} this
34929 this.on("click", this.handler, this.scope, true);
34933 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34935 * @cfg {Function} handler
34936 * A function that will handle the click event of this menu item (defaults to undefined)
34939 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34941 canActivate : false,
34943 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34945 activeClass : "x-menu-item-active",
34947 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34949 hideOnClick : true,
34951 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34956 ctype: "Roo.menu.BaseItem",
34959 actionMode : "container",
34962 render : function(container, parentMenu){
34963 this.parentMenu = parentMenu;
34964 Roo.menu.BaseItem.superclass.render.call(this, container);
34965 this.container.menuItemId = this.id;
34969 onRender : function(container, position){
34970 this.el = Roo.get(this.el);
34971 container.dom.appendChild(this.el.dom);
34975 onClick : function(e){
34976 if(!this.disabled && this.fireEvent("click", this, e) !== false
34977 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34978 this.handleClick(e);
34985 activate : function(){
34989 var li = this.container;
34990 li.addClass(this.activeClass);
34991 this.region = li.getRegion().adjust(2, 2, -2, -2);
34992 this.fireEvent("activate", this);
34997 deactivate : function(){
34998 this.container.removeClass(this.activeClass);
34999 this.fireEvent("deactivate", this);
35003 shouldDeactivate : function(e){
35004 return !this.region || !this.region.contains(e.getPoint());
35008 handleClick : function(e){
35009 if(this.hideOnClick){
35010 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35015 expandMenu : function(autoActivate){
35020 hideMenu : function(){
35025 * Ext JS Library 1.1.1
35026 * Copyright(c) 2006-2007, Ext JS, LLC.
35028 * Originally Released Under LGPL - original licence link has changed is not relivant.
35031 * <script type="text/javascript">
35035 * @class Roo.menu.Adapter
35036 * @extends Roo.menu.BaseItem
35037 * 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.
35038 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35040 * Creates a new Adapter
35041 * @param {Object} config Configuration options
35043 Roo.menu.Adapter = function(component, config){
35044 Roo.menu.Adapter.superclass.constructor.call(this, config);
35045 this.component = component;
35047 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35049 canActivate : true,
35052 onRender : function(container, position){
35053 this.component.render(container);
35054 this.el = this.component.getEl();
35058 activate : function(){
35062 this.component.focus();
35063 this.fireEvent("activate", this);
35068 deactivate : function(){
35069 this.fireEvent("deactivate", this);
35073 disable : function(){
35074 this.component.disable();
35075 Roo.menu.Adapter.superclass.disable.call(this);
35079 enable : function(){
35080 this.component.enable();
35081 Roo.menu.Adapter.superclass.enable.call(this);
35085 * Ext JS Library 1.1.1
35086 * Copyright(c) 2006-2007, Ext JS, LLC.
35088 * Originally Released Under LGPL - original licence link has changed is not relivant.
35091 * <script type="text/javascript">
35095 * @class Roo.menu.TextItem
35096 * @extends Roo.menu.BaseItem
35097 * Adds a static text string to a menu, usually used as either a heading or group separator.
35098 * Note: old style constructor with text is still supported.
35101 * Creates a new TextItem
35102 * @param {Object} cfg Configuration
35104 Roo.menu.TextItem = function(cfg){
35105 if (typeof(cfg) == 'string') {
35108 Roo.apply(this,cfg);
35111 Roo.menu.TextItem.superclass.constructor.call(this);
35114 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35116 * @cfg {Boolean} text Text to show on item.
35121 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35123 hideOnClick : false,
35125 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35127 itemCls : "x-menu-text",
35130 onRender : function(){
35131 var s = document.createElement("span");
35132 s.className = this.itemCls;
35133 s.innerHTML = this.text;
35135 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35139 * Ext JS Library 1.1.1
35140 * Copyright(c) 2006-2007, Ext JS, LLC.
35142 * Originally Released Under LGPL - original licence link has changed is not relivant.
35145 * <script type="text/javascript">
35149 * @class Roo.menu.Separator
35150 * @extends Roo.menu.BaseItem
35151 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35152 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35154 * @param {Object} config Configuration options
35156 Roo.menu.Separator = function(config){
35157 Roo.menu.Separator.superclass.constructor.call(this, config);
35160 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35162 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35164 itemCls : "x-menu-sep",
35166 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35168 hideOnClick : false,
35171 onRender : function(li){
35172 var s = document.createElement("span");
35173 s.className = this.itemCls;
35174 s.innerHTML = " ";
35176 li.addClass("x-menu-sep-li");
35177 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35181 * Ext JS Library 1.1.1
35182 * Copyright(c) 2006-2007, Ext JS, LLC.
35184 * Originally Released Under LGPL - original licence link has changed is not relivant.
35187 * <script type="text/javascript">
35190 * @class Roo.menu.Item
35191 * @extends Roo.menu.BaseItem
35192 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35193 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35194 * activation and click handling.
35196 * Creates a new Item
35197 * @param {Object} config Configuration options
35199 Roo.menu.Item = function(config){
35200 Roo.menu.Item.superclass.constructor.call(this, config);
35202 this.menu = Roo.menu.MenuMgr.get(this.menu);
35205 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35208 * @cfg {String} text
35209 * The text to show on the menu item.
35213 * @cfg {String} HTML to render in menu
35214 * The text to show on the menu item (HTML version).
35218 * @cfg {String} icon
35219 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35223 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35225 itemCls : "x-menu-item",
35227 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35229 canActivate : true,
35231 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35234 // doc'd in BaseItem
35238 ctype: "Roo.menu.Item",
35241 onRender : function(container, position){
35242 var el = document.createElement("a");
35243 el.hideFocus = true;
35244 el.unselectable = "on";
35245 el.href = this.href || "#";
35246 if(this.hrefTarget){
35247 el.target = this.hrefTarget;
35249 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35251 var html = this.html.length ? this.html : String.format('{0}',this.text);
35253 el.innerHTML = String.format(
35254 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35255 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35257 Roo.menu.Item.superclass.onRender.call(this, container, position);
35261 * Sets the text to display in this menu item
35262 * @param {String} text The text to display
35263 * @param {Boolean} isHTML true to indicate text is pure html.
35265 setText : function(text, isHTML){
35273 var html = this.html.length ? this.html : String.format('{0}',this.text);
35275 this.el.update(String.format(
35276 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35277 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35278 this.parentMenu.autoWidth();
35283 handleClick : function(e){
35284 if(!this.href){ // if no link defined, stop the event automatically
35287 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35291 activate : function(autoExpand){
35292 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35302 shouldDeactivate : function(e){
35303 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35304 if(this.menu && this.menu.isVisible()){
35305 return !this.menu.getEl().getRegion().contains(e.getPoint());
35313 deactivate : function(){
35314 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35319 expandMenu : function(autoActivate){
35320 if(!this.disabled && this.menu){
35321 clearTimeout(this.hideTimer);
35322 delete this.hideTimer;
35323 if(!this.menu.isVisible() && !this.showTimer){
35324 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35325 }else if (this.menu.isVisible() && autoActivate){
35326 this.menu.tryActivate(0, 1);
35332 deferExpand : function(autoActivate){
35333 delete this.showTimer;
35334 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35336 this.menu.tryActivate(0, 1);
35341 hideMenu : function(){
35342 clearTimeout(this.showTimer);
35343 delete this.showTimer;
35344 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35345 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35350 deferHide : function(){
35351 delete this.hideTimer;
35356 * Ext JS Library 1.1.1
35357 * Copyright(c) 2006-2007, Ext JS, LLC.
35359 * Originally Released Under LGPL - original licence link has changed is not relivant.
35362 * <script type="text/javascript">
35366 * @class Roo.menu.CheckItem
35367 * @extends Roo.menu.Item
35368 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35370 * Creates a new CheckItem
35371 * @param {Object} config Configuration options
35373 Roo.menu.CheckItem = function(config){
35374 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35377 * @event beforecheckchange
35378 * Fires before the checked value is set, providing an opportunity to cancel if needed
35379 * @param {Roo.menu.CheckItem} this
35380 * @param {Boolean} checked The new checked value that will be set
35382 "beforecheckchange" : true,
35384 * @event checkchange
35385 * Fires after the checked value has been set
35386 * @param {Roo.menu.CheckItem} this
35387 * @param {Boolean} checked The checked value that was set
35389 "checkchange" : true
35391 if(this.checkHandler){
35392 this.on('checkchange', this.checkHandler, this.scope);
35395 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35397 * @cfg {String} group
35398 * All check items with the same group name will automatically be grouped into a single-select
35399 * radio button group (defaults to '')
35402 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35404 itemCls : "x-menu-item x-menu-check-item",
35406 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35408 groupClass : "x-menu-group-item",
35411 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35412 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35413 * initialized with checked = true will be rendered as checked.
35418 ctype: "Roo.menu.CheckItem",
35421 onRender : function(c){
35422 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35424 this.el.addClass(this.groupClass);
35426 Roo.menu.MenuMgr.registerCheckable(this);
35428 this.checked = false;
35429 this.setChecked(true, true);
35434 destroy : function(){
35436 Roo.menu.MenuMgr.unregisterCheckable(this);
35438 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35442 * Set the checked state of this item
35443 * @param {Boolean} checked The new checked value
35444 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35446 setChecked : function(state, suppressEvent){
35447 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35448 if(this.container){
35449 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35451 this.checked = state;
35452 if(suppressEvent !== true){
35453 this.fireEvent("checkchange", this, state);
35459 handleClick : function(e){
35460 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35461 this.setChecked(!this.checked);
35463 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35467 * Ext JS Library 1.1.1
35468 * Copyright(c) 2006-2007, Ext JS, LLC.
35470 * Originally Released Under LGPL - original licence link has changed is not relivant.
35473 * <script type="text/javascript">
35477 * @class Roo.menu.DateItem
35478 * @extends Roo.menu.Adapter
35479 * A menu item that wraps the {@link Roo.DatPicker} component.
35481 * Creates a new DateItem
35482 * @param {Object} config Configuration options
35484 Roo.menu.DateItem = function(config){
35485 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35486 /** The Roo.DatePicker object @type Roo.DatePicker */
35487 this.picker = this.component;
35488 this.addEvents({select: true});
35490 this.picker.on("render", function(picker){
35491 picker.getEl().swallowEvent("click");
35492 picker.container.addClass("x-menu-date-item");
35495 this.picker.on("select", this.onSelect, this);
35498 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35500 onSelect : function(picker, date){
35501 this.fireEvent("select", this, date, picker);
35502 Roo.menu.DateItem.superclass.handleClick.call(this);
35506 * Ext JS Library 1.1.1
35507 * Copyright(c) 2006-2007, Ext JS, LLC.
35509 * Originally Released Under LGPL - original licence link has changed is not relivant.
35512 * <script type="text/javascript">
35516 * @class Roo.menu.ColorItem
35517 * @extends Roo.menu.Adapter
35518 * A menu item that wraps the {@link Roo.ColorPalette} component.
35520 * Creates a new ColorItem
35521 * @param {Object} config Configuration options
35523 Roo.menu.ColorItem = function(config){
35524 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35525 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35526 this.palette = this.component;
35527 this.relayEvents(this.palette, ["select"]);
35528 if(this.selectHandler){
35529 this.on('select', this.selectHandler, this.scope);
35532 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35534 * Ext JS Library 1.1.1
35535 * Copyright(c) 2006-2007, Ext JS, LLC.
35537 * Originally Released Under LGPL - original licence link has changed is not relivant.
35540 * <script type="text/javascript">
35545 * @class Roo.menu.DateMenu
35546 * @extends Roo.menu.Menu
35547 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35549 * Creates a new DateMenu
35550 * @param {Object} config Configuration options
35552 Roo.menu.DateMenu = function(config){
35553 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35555 var di = new Roo.menu.DateItem(config);
35558 * The {@link Roo.DatePicker} instance for this DateMenu
35561 this.picker = di.picker;
35564 * @param {DatePicker} picker
35565 * @param {Date} date
35567 this.relayEvents(di, ["select"]);
35569 this.on('beforeshow', function(){
35571 this.picker.hideMonthPicker(true);
35575 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35579 * Ext JS Library 1.1.1
35580 * Copyright(c) 2006-2007, Ext JS, LLC.
35582 * Originally Released Under LGPL - original licence link has changed is not relivant.
35585 * <script type="text/javascript">
35590 * @class Roo.menu.ColorMenu
35591 * @extends Roo.menu.Menu
35592 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35594 * Creates a new ColorMenu
35595 * @param {Object} config Configuration options
35597 Roo.menu.ColorMenu = function(config){
35598 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35600 var ci = new Roo.menu.ColorItem(config);
35603 * The {@link Roo.ColorPalette} instance for this ColorMenu
35604 * @type ColorPalette
35606 this.palette = ci.palette;
35609 * @param {ColorPalette} palette
35610 * @param {String} color
35612 this.relayEvents(ci, ["select"]);
35614 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35616 * Ext JS Library 1.1.1
35617 * Copyright(c) 2006-2007, Ext JS, LLC.
35619 * Originally Released Under LGPL - original licence link has changed is not relivant.
35622 * <script type="text/javascript">
35626 * @class Roo.form.Field
35627 * @extends Roo.BoxComponent
35628 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35630 * Creates a new Field
35631 * @param {Object} config Configuration options
35633 Roo.form.Field = function(config){
35634 Roo.form.Field.superclass.constructor.call(this, config);
35637 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35639 * @cfg {String} fieldLabel Label to use when rendering a form.
35642 * @cfg {String} qtip Mouse over tip
35646 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35648 invalidClass : "x-form-invalid",
35650 * @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")
35652 invalidText : "The value in this field is invalid",
35654 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35656 focusClass : "x-form-focus",
35658 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35659 automatic validation (defaults to "keyup").
35661 validationEvent : "keyup",
35663 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35665 validateOnBlur : true,
35667 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35669 validationDelay : 250,
35671 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35672 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35674 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35676 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35678 fieldClass : "x-form-field",
35680 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35683 ----------- ----------------------------------------------------------------------
35684 qtip Display a quick tip when the user hovers over the field
35685 title Display a default browser title attribute popup
35686 under Add a block div beneath the field containing the error text
35687 side Add an error icon to the right of the field with a popup on hover
35688 [element id] Add the error text directly to the innerHTML of the specified element
35691 msgTarget : 'qtip',
35693 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35698 * @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.
35703 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35708 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35710 inputType : undefined,
35713 * @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).
35715 tabIndex : undefined,
35718 isFormField : true,
35723 * @property {Roo.Element} fieldEl
35724 * Element Containing the rendered Field (with label etc.)
35727 * @cfg {Mixed} value A value to initialize this field with.
35732 * @cfg {String} name The field's HTML name attribute.
35735 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35739 initComponent : function(){
35740 Roo.form.Field.superclass.initComponent.call(this);
35744 * Fires when this field receives input focus.
35745 * @param {Roo.form.Field} this
35750 * Fires when this field loses input focus.
35751 * @param {Roo.form.Field} this
35755 * @event specialkey
35756 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35757 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35758 * @param {Roo.form.Field} this
35759 * @param {Roo.EventObject} e The event object
35764 * Fires just before the field blurs if the field value has changed.
35765 * @param {Roo.form.Field} this
35766 * @param {Mixed} newValue The new value
35767 * @param {Mixed} oldValue The original value
35772 * Fires after the field has been marked as invalid.
35773 * @param {Roo.form.Field} this
35774 * @param {String} msg The validation message
35779 * Fires after the field has been validated with no errors.
35780 * @param {Roo.form.Field} this
35785 * Fires after the key up
35786 * @param {Roo.form.Field} this
35787 * @param {Roo.EventObject} e The event Object
35794 * Returns the name attribute of the field if available
35795 * @return {String} name The field name
35797 getName: function(){
35798 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35802 onRender : function(ct, position){
35803 Roo.form.Field.superclass.onRender.call(this, ct, position);
35805 var cfg = this.getAutoCreate();
35807 cfg.name = this.name || this.id;
35809 if(this.inputType){
35810 cfg.type = this.inputType;
35812 this.el = ct.createChild(cfg, position);
35814 var type = this.el.dom.type;
35816 if(type == 'password'){
35819 this.el.addClass('x-form-'+type);
35822 this.el.dom.readOnly = true;
35824 if(this.tabIndex !== undefined){
35825 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35828 this.el.addClass([this.fieldClass, this.cls]);
35833 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35834 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35835 * @return {Roo.form.Field} this
35837 applyTo : function(target){
35838 this.allowDomMove = false;
35839 this.el = Roo.get(target);
35840 this.render(this.el.dom.parentNode);
35845 initValue : function(){
35846 if(this.value !== undefined){
35847 this.setValue(this.value);
35848 }else if(this.el.dom.value.length > 0){
35849 this.setValue(this.el.dom.value);
35854 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35856 isDirty : function() {
35857 if(this.disabled) {
35860 return String(this.getValue()) !== String(this.originalValue);
35864 afterRender : function(){
35865 Roo.form.Field.superclass.afterRender.call(this);
35870 fireKey : function(e){
35871 //Roo.log('field ' + e.getKey());
35872 if(e.isNavKeyPress()){
35873 this.fireEvent("specialkey", this, e);
35878 * Resets the current field value to the originally loaded value and clears any validation messages
35880 reset : function(){
35881 this.setValue(this.originalValue);
35882 this.clearInvalid();
35886 initEvents : function(){
35887 // safari killled keypress - so keydown is now used..
35888 this.el.on("keydown" , this.fireKey, this);
35889 this.el.on("focus", this.onFocus, this);
35890 this.el.on("blur", this.onBlur, this);
35891 this.el.relayEvent('keyup', this);
35893 // reference to original value for reset
35894 this.originalValue = this.getValue();
35898 onFocus : function(){
35899 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35900 this.el.addClass(this.focusClass);
35902 if(!this.hasFocus){
35903 this.hasFocus = true;
35904 this.startValue = this.getValue();
35905 this.fireEvent("focus", this);
35909 beforeBlur : Roo.emptyFn,
35912 onBlur : function(){
35914 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35915 this.el.removeClass(this.focusClass);
35917 this.hasFocus = false;
35918 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35921 var v = this.getValue();
35922 if(String(v) !== String(this.startValue)){
35923 this.fireEvent('change', this, v, this.startValue);
35925 this.fireEvent("blur", this);
35929 * Returns whether or not the field value is currently valid
35930 * @param {Boolean} preventMark True to disable marking the field invalid
35931 * @return {Boolean} True if the value is valid, else false
35933 isValid : function(preventMark){
35937 var restore = this.preventMark;
35938 this.preventMark = preventMark === true;
35939 var v = this.validateValue(this.processValue(this.getRawValue()));
35940 this.preventMark = restore;
35945 * Validates the field value
35946 * @return {Boolean} True if the value is valid, else false
35948 validate : function(){
35949 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35950 this.clearInvalid();
35956 processValue : function(value){
35961 // Subclasses should provide the validation implementation by overriding this
35962 validateValue : function(value){
35967 * Mark this field as invalid
35968 * @param {String} msg The validation message
35970 markInvalid : function(msg){
35971 if(!this.rendered || this.preventMark){ // not rendered
35974 this.el.addClass(this.invalidClass);
35975 msg = msg || this.invalidText;
35976 switch(this.msgTarget){
35978 this.el.dom.qtip = msg;
35979 this.el.dom.qclass = 'x-form-invalid-tip';
35980 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35981 Roo.QuickTips.enable();
35985 this.el.dom.title = msg;
35989 var elp = this.el.findParent('.x-form-element', 5, true);
35990 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35991 this.errorEl.setWidth(elp.getWidth(true)-20);
35993 this.errorEl.update(msg);
35994 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35997 if(!this.errorIcon){
35998 var elp = this.el.findParent('.x-form-element', 5, true);
35999 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36001 this.alignErrorIcon();
36002 this.errorIcon.dom.qtip = msg;
36003 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36004 this.errorIcon.show();
36005 this.on('resize', this.alignErrorIcon, this);
36008 var t = Roo.getDom(this.msgTarget);
36010 t.style.display = this.msgDisplay;
36013 this.fireEvent('invalid', this, msg);
36017 alignErrorIcon : function(){
36018 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36022 * Clear any invalid styles/messages for this field
36024 clearInvalid : function(){
36025 if(!this.rendered || this.preventMark){ // not rendered
36028 this.el.removeClass(this.invalidClass);
36029 switch(this.msgTarget){
36031 this.el.dom.qtip = '';
36034 this.el.dom.title = '';
36038 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36042 if(this.errorIcon){
36043 this.errorIcon.dom.qtip = '';
36044 this.errorIcon.hide();
36045 this.un('resize', this.alignErrorIcon, this);
36049 var t = Roo.getDom(this.msgTarget);
36051 t.style.display = 'none';
36054 this.fireEvent('valid', this);
36058 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36059 * @return {Mixed} value The field value
36061 getRawValue : function(){
36062 var v = this.el.getValue();
36063 if(v === this.emptyText){
36070 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36071 * @return {Mixed} value The field value
36073 getValue : function(){
36074 var v = this.el.getValue();
36075 if(v === this.emptyText || v === undefined){
36082 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36083 * @param {Mixed} value The value to set
36085 setRawValue : function(v){
36086 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36090 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36091 * @param {Mixed} value The value to set
36093 setValue : function(v){
36096 this.el.dom.value = (v === null || v === undefined ? '' : v);
36101 adjustSize : function(w, h){
36102 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36103 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36107 adjustWidth : function(tag, w){
36108 tag = tag.toLowerCase();
36109 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36110 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36111 if(tag == 'input'){
36114 if(tag = 'textarea'){
36117 }else if(Roo.isOpera){
36118 if(tag == 'input'){
36121 if(tag = 'textarea'){
36131 // anything other than normal should be considered experimental
36132 Roo.form.Field.msgFx = {
36134 show: function(msgEl, f){
36135 msgEl.setDisplayed('block');
36138 hide : function(msgEl, f){
36139 msgEl.setDisplayed(false).update('');
36144 show: function(msgEl, f){
36145 msgEl.slideIn('t', {stopFx:true});
36148 hide : function(msgEl, f){
36149 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36154 show: function(msgEl, f){
36155 msgEl.fixDisplay();
36156 msgEl.alignTo(f.el, 'tl-tr');
36157 msgEl.slideIn('l', {stopFx:true});
36160 hide : function(msgEl, f){
36161 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36166 * Ext JS Library 1.1.1
36167 * Copyright(c) 2006-2007, Ext JS, LLC.
36169 * Originally Released Under LGPL - original licence link has changed is not relivant.
36172 * <script type="text/javascript">
36177 * @class Roo.form.TextField
36178 * @extends Roo.form.Field
36179 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36180 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36182 * Creates a new TextField
36183 * @param {Object} config Configuration options
36185 Roo.form.TextField = function(config){
36186 Roo.form.TextField.superclass.constructor.call(this, config);
36190 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36191 * according to the default logic, but this event provides a hook for the developer to apply additional
36192 * logic at runtime to resize the field if needed.
36193 * @param {Roo.form.Field} this This text field
36194 * @param {Number} width The new field width
36200 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36202 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36206 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36210 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36214 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36218 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36222 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36224 disableKeyFilter : false,
36226 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36230 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36234 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36236 maxLength : Number.MAX_VALUE,
36238 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36240 minLengthText : "The minimum length for this field is {0}",
36242 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36244 maxLengthText : "The maximum length for this field is {0}",
36246 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36248 selectOnFocus : false,
36250 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36252 blankText : "This field is required",
36254 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36255 * If available, this function will be called only after the basic validators all return true, and will be passed the
36256 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36260 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36261 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36262 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36266 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36270 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36274 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36275 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36277 emptyClass : 'x-form-empty-field',
36280 initEvents : function(){
36281 Roo.form.TextField.superclass.initEvents.call(this);
36282 if(this.validationEvent == 'keyup'){
36283 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36284 this.el.on('keyup', this.filterValidation, this);
36286 else if(this.validationEvent !== false){
36287 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36289 if(this.selectOnFocus || this.emptyText){
36290 this.on("focus", this.preFocus, this);
36291 if(this.emptyText){
36292 this.on('blur', this.postBlur, this);
36293 this.applyEmptyText();
36296 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36297 this.el.on("keypress", this.filterKeys, this);
36300 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36301 this.el.on("click", this.autoSize, this);
36305 processValue : function(value){
36306 if(this.stripCharsRe){
36307 var newValue = value.replace(this.stripCharsRe, '');
36308 if(newValue !== value){
36309 this.setRawValue(newValue);
36316 filterValidation : function(e){
36317 if(!e.isNavKeyPress()){
36318 this.validationTask.delay(this.validationDelay);
36323 onKeyUp : function(e){
36324 if(!e.isNavKeyPress()){
36330 * Resets the current field value to the originally-loaded value and clears any validation messages.
36331 * Also adds emptyText and emptyClass if the original value was blank.
36333 reset : function(){
36334 Roo.form.TextField.superclass.reset.call(this);
36335 this.applyEmptyText();
36338 applyEmptyText : function(){
36339 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36340 this.setRawValue(this.emptyText);
36341 this.el.addClass(this.emptyClass);
36346 preFocus : function(){
36347 if(this.emptyText){
36348 if(this.el.dom.value == this.emptyText){
36349 this.setRawValue('');
36351 this.el.removeClass(this.emptyClass);
36353 if(this.selectOnFocus){
36354 this.el.dom.select();
36359 postBlur : function(){
36360 this.applyEmptyText();
36364 filterKeys : function(e){
36365 var k = e.getKey();
36366 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36369 var c = e.getCharCode(), cc = String.fromCharCode(c);
36370 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36373 if(!this.maskRe.test(cc)){
36378 setValue : function(v){
36379 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36380 this.el.removeClass(this.emptyClass);
36382 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36383 this.applyEmptyText();
36388 * Validates a value according to the field's validation rules and marks the field as invalid
36389 * if the validation fails
36390 * @param {Mixed} value The value to validate
36391 * @return {Boolean} True if the value is valid, else false
36393 validateValue : function(value){
36394 if(value.length < 1 || value === this.emptyText){ // if it's blank
36395 if(this.allowBlank){
36396 this.clearInvalid();
36399 this.markInvalid(this.blankText);
36403 if(value.length < this.minLength){
36404 this.markInvalid(String.format(this.minLengthText, this.minLength));
36407 if(value.length > this.maxLength){
36408 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36412 var vt = Roo.form.VTypes;
36413 if(!vt[this.vtype](value, this)){
36414 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36418 if(typeof this.validator == "function"){
36419 var msg = this.validator(value);
36421 this.markInvalid(msg);
36425 if(this.regex && !this.regex.test(value)){
36426 this.markInvalid(this.regexText);
36433 * Selects text in this field
36434 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36435 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36437 selectText : function(start, end){
36438 var v = this.getRawValue();
36440 start = start === undefined ? 0 : start;
36441 end = end === undefined ? v.length : end;
36442 var d = this.el.dom;
36443 if(d.setSelectionRange){
36444 d.setSelectionRange(start, end);
36445 }else if(d.createTextRange){
36446 var range = d.createTextRange();
36447 range.moveStart("character", start);
36448 range.moveEnd("character", v.length-end);
36455 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36456 * This only takes effect if grow = true, and fires the autosize event.
36458 autoSize : function(){
36459 if(!this.grow || !this.rendered){
36463 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36466 var v = el.dom.value;
36467 var d = document.createElement('div');
36468 d.appendChild(document.createTextNode(v));
36472 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36473 this.el.setWidth(w);
36474 this.fireEvent("autosize", this, w);
36478 * Ext JS Library 1.1.1
36479 * Copyright(c) 2006-2007, Ext JS, LLC.
36481 * Originally Released Under LGPL - original licence link has changed is not relivant.
36484 * <script type="text/javascript">
36488 * @class Roo.form.Hidden
36489 * @extends Roo.form.TextField
36490 * Simple Hidden element used on forms
36492 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36495 * Creates a new Hidden form element.
36496 * @param {Object} config Configuration options
36501 // easy hidden field...
36502 Roo.form.Hidden = function(config){
36503 Roo.form.Hidden.superclass.constructor.call(this, config);
36506 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36508 inputType: 'hidden',
36511 labelSeparator: '',
36513 itemCls : 'x-form-item-display-none'
36521 * Ext JS Library 1.1.1
36522 * Copyright(c) 2006-2007, Ext JS, LLC.
36524 * Originally Released Under LGPL - original licence link has changed is not relivant.
36527 * <script type="text/javascript">
36531 * @class Roo.form.TriggerField
36532 * @extends Roo.form.TextField
36533 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36534 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36535 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36536 * for which you can provide a custom implementation. For example:
36538 var trigger = new Roo.form.TriggerField();
36539 trigger.onTriggerClick = myTriggerFn;
36540 trigger.applyTo('my-field');
36543 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36544 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36545 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36546 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36548 * Create a new TriggerField.
36549 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36550 * to the base TextField)
36552 Roo.form.TriggerField = function(config){
36553 this.mimicing = false;
36554 Roo.form.TriggerField.superclass.constructor.call(this, config);
36557 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36559 * @cfg {String} triggerClass A CSS class to apply to the trigger
36562 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36563 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36565 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36567 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36571 /** @cfg {Boolean} grow @hide */
36572 /** @cfg {Number} growMin @hide */
36573 /** @cfg {Number} growMax @hide */
36579 autoSize: Roo.emptyFn,
36583 deferHeight : true,
36586 actionMode : 'wrap',
36588 onResize : function(w, h){
36589 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36590 if(typeof w == 'number'){
36591 var x = w - this.trigger.getWidth();
36592 this.el.setWidth(this.adjustWidth('input', x));
36593 this.trigger.setStyle('left', x+'px');
36598 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36601 getResizeEl : function(){
36606 getPositionEl : function(){
36611 alignErrorIcon : function(){
36612 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36616 onRender : function(ct, position){
36617 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36618 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36619 this.trigger = this.wrap.createChild(this.triggerConfig ||
36620 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36621 if(this.hideTrigger){
36622 this.trigger.setDisplayed(false);
36624 this.initTrigger();
36626 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36631 initTrigger : function(){
36632 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36633 this.trigger.addClassOnOver('x-form-trigger-over');
36634 this.trigger.addClassOnClick('x-form-trigger-click');
36638 onDestroy : function(){
36640 this.trigger.removeAllListeners();
36641 this.trigger.remove();
36644 this.wrap.remove();
36646 Roo.form.TriggerField.superclass.onDestroy.call(this);
36650 onFocus : function(){
36651 Roo.form.TriggerField.superclass.onFocus.call(this);
36652 if(!this.mimicing){
36653 this.wrap.addClass('x-trigger-wrap-focus');
36654 this.mimicing = true;
36655 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36656 if(this.monitorTab){
36657 this.el.on("keydown", this.checkTab, this);
36663 checkTab : function(e){
36664 if(e.getKey() == e.TAB){
36665 this.triggerBlur();
36670 onBlur : function(){
36675 mimicBlur : function(e, t){
36676 if(!this.wrap.contains(t) && this.validateBlur()){
36677 this.triggerBlur();
36682 triggerBlur : function(){
36683 this.mimicing = false;
36684 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36685 if(this.monitorTab){
36686 this.el.un("keydown", this.checkTab, this);
36688 this.wrap.removeClass('x-trigger-wrap-focus');
36689 Roo.form.TriggerField.superclass.onBlur.call(this);
36693 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36694 validateBlur : function(e, t){
36699 onDisable : function(){
36700 Roo.form.TriggerField.superclass.onDisable.call(this);
36702 this.wrap.addClass('x-item-disabled');
36707 onEnable : function(){
36708 Roo.form.TriggerField.superclass.onEnable.call(this);
36710 this.wrap.removeClass('x-item-disabled');
36715 onShow : function(){
36716 var ae = this.getActionEl();
36719 ae.dom.style.display = '';
36720 ae.dom.style.visibility = 'visible';
36726 onHide : function(){
36727 var ae = this.getActionEl();
36728 ae.dom.style.display = 'none';
36732 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36733 * by an implementing function.
36735 * @param {EventObject} e
36737 onTriggerClick : Roo.emptyFn
36740 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36741 // to be extended by an implementing class. For an example of implementing this class, see the custom
36742 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36743 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36744 initComponent : function(){
36745 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36747 this.triggerConfig = {
36748 tag:'span', cls:'x-form-twin-triggers', cn:[
36749 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36750 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36754 getTrigger : function(index){
36755 return this.triggers[index];
36758 initTrigger : function(){
36759 var ts = this.trigger.select('.x-form-trigger', true);
36760 this.wrap.setStyle('overflow', 'hidden');
36761 var triggerField = this;
36762 ts.each(function(t, all, index){
36763 t.hide = function(){
36764 var w = triggerField.wrap.getWidth();
36765 this.dom.style.display = 'none';
36766 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36768 t.show = function(){
36769 var w = triggerField.wrap.getWidth();
36770 this.dom.style.display = '';
36771 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36773 var triggerIndex = 'Trigger'+(index+1);
36775 if(this['hide'+triggerIndex]){
36776 t.dom.style.display = 'none';
36778 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36779 t.addClassOnOver('x-form-trigger-over');
36780 t.addClassOnClick('x-form-trigger-click');
36782 this.triggers = ts.elements;
36785 onTrigger1Click : Roo.emptyFn,
36786 onTrigger2Click : Roo.emptyFn
36789 * Ext JS Library 1.1.1
36790 * Copyright(c) 2006-2007, Ext JS, LLC.
36792 * Originally Released Under LGPL - original licence link has changed is not relivant.
36795 * <script type="text/javascript">
36799 * @class Roo.form.TextArea
36800 * @extends Roo.form.TextField
36801 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36802 * support for auto-sizing.
36804 * Creates a new TextArea
36805 * @param {Object} config Configuration options
36807 Roo.form.TextArea = function(config){
36808 Roo.form.TextArea.superclass.constructor.call(this, config);
36809 // these are provided exchanges for backwards compat
36810 // minHeight/maxHeight were replaced by growMin/growMax to be
36811 // compatible with TextField growing config values
36812 if(this.minHeight !== undefined){
36813 this.growMin = this.minHeight;
36815 if(this.maxHeight !== undefined){
36816 this.growMax = this.maxHeight;
36820 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36822 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36826 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36830 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36831 * in the field (equivalent to setting overflow: hidden, defaults to false)
36833 preventScrollbars: false,
36835 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36836 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36840 onRender : function(ct, position){
36842 this.defaultAutoCreate = {
36844 style:"width:300px;height:60px;",
36845 autocomplete: "off"
36848 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36850 this.textSizeEl = Roo.DomHelper.append(document.body, {
36851 tag: "pre", cls: "x-form-grow-sizer"
36853 if(this.preventScrollbars){
36854 this.el.setStyle("overflow", "hidden");
36856 this.el.setHeight(this.growMin);
36860 onDestroy : function(){
36861 if(this.textSizeEl){
36862 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36864 Roo.form.TextArea.superclass.onDestroy.call(this);
36868 onKeyUp : function(e){
36869 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36875 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36876 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36878 autoSize : function(){
36879 if(!this.grow || !this.textSizeEl){
36883 var v = el.dom.value;
36884 var ts = this.textSizeEl;
36887 ts.appendChild(document.createTextNode(v));
36890 Roo.fly(ts).setWidth(this.el.getWidth());
36892 v = "  ";
36895 v = v.replace(/\n/g, '<p> </p>');
36897 v += " \n ";
36900 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36901 if(h != this.lastHeight){
36902 this.lastHeight = h;
36903 this.el.setHeight(h);
36904 this.fireEvent("autosize", this, h);
36909 * Ext JS Library 1.1.1
36910 * Copyright(c) 2006-2007, Ext JS, LLC.
36912 * Originally Released Under LGPL - original licence link has changed is not relivant.
36915 * <script type="text/javascript">
36920 * @class Roo.form.NumberField
36921 * @extends Roo.form.TextField
36922 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36924 * Creates a new NumberField
36925 * @param {Object} config Configuration options
36927 Roo.form.NumberField = function(config){
36928 Roo.form.NumberField.superclass.constructor.call(this, config);
36931 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36933 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36935 fieldClass: "x-form-field x-form-num-field",
36937 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36939 allowDecimals : true,
36941 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36943 decimalSeparator : ".",
36945 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36947 decimalPrecision : 2,
36949 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36951 allowNegative : true,
36953 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36955 minValue : Number.NEGATIVE_INFINITY,
36957 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36959 maxValue : Number.MAX_VALUE,
36961 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36963 minText : "The minimum value for this field is {0}",
36965 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36967 maxText : "The maximum value for this field is {0}",
36969 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36970 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36972 nanText : "{0} is not a valid number",
36975 initEvents : function(){
36976 Roo.form.NumberField.superclass.initEvents.call(this);
36977 var allowed = "0123456789";
36978 if(this.allowDecimals){
36979 allowed += this.decimalSeparator;
36981 if(this.allowNegative){
36984 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36985 var keyPress = function(e){
36986 var k = e.getKey();
36987 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36990 var c = e.getCharCode();
36991 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36995 this.el.on("keypress", keyPress, this);
36999 validateValue : function(value){
37000 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37003 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37006 var num = this.parseValue(value);
37008 this.markInvalid(String.format(this.nanText, value));
37011 if(num < this.minValue){
37012 this.markInvalid(String.format(this.minText, this.minValue));
37015 if(num > this.maxValue){
37016 this.markInvalid(String.format(this.maxText, this.maxValue));
37022 getValue : function(){
37023 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37027 parseValue : function(value){
37028 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37029 return isNaN(value) ? '' : value;
37033 fixPrecision : function(value){
37034 var nan = isNaN(value);
37035 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37036 return nan ? '' : value;
37038 return parseFloat(value).toFixed(this.decimalPrecision);
37041 setValue : function(v){
37042 v = this.fixPrecision(v);
37043 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37047 decimalPrecisionFcn : function(v){
37048 return Math.floor(v);
37051 beforeBlur : function(){
37052 var v = this.parseValue(this.getRawValue());
37059 * Ext JS Library 1.1.1
37060 * Copyright(c) 2006-2007, Ext JS, LLC.
37062 * Originally Released Under LGPL - original licence link has changed is not relivant.
37065 * <script type="text/javascript">
37069 * @class Roo.form.DateField
37070 * @extends Roo.form.TriggerField
37071 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37073 * Create a new DateField
37074 * @param {Object} config
37076 Roo.form.DateField = function(config){
37077 Roo.form.DateField.superclass.constructor.call(this, config);
37083 * Fires when a date is selected
37084 * @param {Roo.form.DateField} combo This combo box
37085 * @param {Date} date The date selected
37092 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37093 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37094 this.ddMatch = null;
37095 if(this.disabledDates){
37096 var dd = this.disabledDates;
37098 for(var i = 0; i < dd.length; i++){
37100 if(i != dd.length-1) re += "|";
37102 this.ddMatch = new RegExp(re + ")");
37106 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37108 * @cfg {String} format
37109 * The default date format string which can be overriden for localization support. The format must be
37110 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37114 * @cfg {String} altFormats
37115 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37116 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37118 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37120 * @cfg {Array} disabledDays
37121 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37123 disabledDays : null,
37125 * @cfg {String} disabledDaysText
37126 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37128 disabledDaysText : "Disabled",
37130 * @cfg {Array} disabledDates
37131 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37132 * expression so they are very powerful. Some examples:
37134 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37135 * <li>["03/08", "09/16"] would disable those days for every year</li>
37136 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37137 * <li>["03/../2006"] would disable every day in March 2006</li>
37138 * <li>["^03"] would disable every day in every March</li>
37140 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37141 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37143 disabledDates : null,
37145 * @cfg {String} disabledDatesText
37146 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37148 disabledDatesText : "Disabled",
37150 * @cfg {Date/String} minValue
37151 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37152 * valid format (defaults to null).
37156 * @cfg {Date/String} maxValue
37157 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37158 * valid format (defaults to null).
37162 * @cfg {String} minText
37163 * The error text to display when the date in the cell is before minValue (defaults to
37164 * 'The date in this field must be after {minValue}').
37166 minText : "The date in this field must be equal to or after {0}",
37168 * @cfg {String} maxText
37169 * The error text to display when the date in the cell is after maxValue (defaults to
37170 * 'The date in this field must be before {maxValue}').
37172 maxText : "The date in this field must be equal to or before {0}",
37174 * @cfg {String} invalidText
37175 * The error text to display when the date in the field is invalid (defaults to
37176 * '{value} is not a valid date - it must be in the format {format}').
37178 invalidText : "{0} is not a valid date - it must be in the format {1}",
37180 * @cfg {String} triggerClass
37181 * An additional CSS class used to style the trigger button. The trigger will always get the
37182 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37183 * which displays a calendar icon).
37185 triggerClass : 'x-form-date-trigger',
37189 * @cfg {bool} useIso
37190 * if enabled, then the date field will use a hidden field to store the
37191 * real value as iso formated date. default (false)
37195 * @cfg {String/Object} autoCreate
37196 * A DomHelper element spec, or true for a default element spec (defaults to
37197 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37200 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37203 hiddenField: false,
37205 onRender : function(ct, position)
37207 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37209 this.el.dom.removeAttribute('name');
37210 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37212 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
37213 // prevent input submission
37214 this.hiddenName = this.name;
37221 validateValue : function(value)
37223 value = this.formatDate(value);
37224 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37227 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37230 var svalue = value;
37231 value = this.parseDate(value);
37233 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37236 var time = value.getTime();
37237 if(this.minValue && time < this.minValue.getTime()){
37238 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37241 if(this.maxValue && time > this.maxValue.getTime()){
37242 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37245 if(this.disabledDays){
37246 var day = value.getDay();
37247 for(var i = 0; i < this.disabledDays.length; i++) {
37248 if(day === this.disabledDays[i]){
37249 this.markInvalid(this.disabledDaysText);
37254 var fvalue = this.formatDate(value);
37255 if(this.ddMatch && this.ddMatch.test(fvalue)){
37256 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37263 // Provides logic to override the default TriggerField.validateBlur which just returns true
37264 validateBlur : function(){
37265 return !this.menu || !this.menu.isVisible();
37269 * Returns the current date value of the date field.
37270 * @return {Date} The date value
37272 getValue : function(){
37274 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37278 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37279 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37280 * (the default format used is "m/d/y").
37283 //All of these calls set the same date value (May 4, 2006)
37285 //Pass a date object:
37286 var dt = new Date('5/4/06');
37287 dateField.setValue(dt);
37289 //Pass a date string (default format):
37290 dateField.setValue('5/4/06');
37292 //Pass a date string (custom format):
37293 dateField.format = 'Y-m-d';
37294 dateField.setValue('2006-5-4');
37296 * @param {String/Date} date The date or valid date string
37298 setValue : function(date){
37299 if (this.hiddenField) {
37300 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37302 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37306 parseDate : function(value){
37307 if(!value || value instanceof Date){
37310 var v = Date.parseDate(value, this.format);
37311 if(!v && this.altFormats){
37312 if(!this.altFormatsArray){
37313 this.altFormatsArray = this.altFormats.split("|");
37315 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37316 v = Date.parseDate(value, this.altFormatsArray[i]);
37323 formatDate : function(date, fmt){
37324 return (!date || !(date instanceof Date)) ?
37325 date : date.dateFormat(fmt || this.format);
37330 select: function(m, d){
37332 this.fireEvent('select', this, d);
37334 show : function(){ // retain focus styling
37338 this.focus.defer(10, this);
37339 var ml = this.menuListeners;
37340 this.menu.un("select", ml.select, this);
37341 this.menu.un("show", ml.show, this);
37342 this.menu.un("hide", ml.hide, this);
37347 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37348 onTriggerClick : function(){
37352 if(this.menu == null){
37353 this.menu = new Roo.menu.DateMenu();
37355 Roo.apply(this.menu.picker, {
37356 showClear: this.allowBlank,
37357 minDate : this.minValue,
37358 maxDate : this.maxValue,
37359 disabledDatesRE : this.ddMatch,
37360 disabledDatesText : this.disabledDatesText,
37361 disabledDays : this.disabledDays,
37362 disabledDaysText : this.disabledDaysText,
37363 format : this.format,
37364 minText : String.format(this.minText, this.formatDate(this.minValue)),
37365 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37367 this.menu.on(Roo.apply({}, this.menuListeners, {
37370 this.menu.picker.setValue(this.getValue() || new Date());
37371 this.menu.show(this.el, "tl-bl?");
37374 beforeBlur : function(){
37375 var v = this.parseDate(this.getRawValue());
37381 /** @cfg {Boolean} grow @hide */
37382 /** @cfg {Number} growMin @hide */
37383 /** @cfg {Number} growMax @hide */
37390 * Ext JS Library 1.1.1
37391 * Copyright(c) 2006-2007, Ext JS, LLC.
37393 * Originally Released Under LGPL - original licence link has changed is not relivant.
37396 * <script type="text/javascript">
37401 * @class Roo.form.ComboBox
37402 * @extends Roo.form.TriggerField
37403 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37405 * Create a new ComboBox.
37406 * @param {Object} config Configuration options
37408 Roo.form.ComboBox = function(config){
37409 Roo.form.ComboBox.superclass.constructor.call(this, config);
37413 * Fires when the dropdown list is expanded
37414 * @param {Roo.form.ComboBox} combo This combo box
37419 * Fires when the dropdown list is collapsed
37420 * @param {Roo.form.ComboBox} combo This combo box
37424 * @event beforeselect
37425 * Fires before a list item is selected. Return false to cancel the selection.
37426 * @param {Roo.form.ComboBox} combo This combo box
37427 * @param {Roo.data.Record} record The data record returned from the underlying store
37428 * @param {Number} index The index of the selected item in the dropdown list
37430 'beforeselect' : true,
37433 * Fires when a list item is selected
37434 * @param {Roo.form.ComboBox} combo This combo box
37435 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37436 * @param {Number} index The index of the selected item in the dropdown list
37440 * @event beforequery
37441 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37442 * The event object passed has these properties:
37443 * @param {Roo.form.ComboBox} combo This combo box
37444 * @param {String} query The query
37445 * @param {Boolean} forceAll true to force "all" query
37446 * @param {Boolean} cancel true to cancel the query
37447 * @param {Object} e The query event object
37449 'beforequery': true,
37452 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37453 * @param {Roo.form.ComboBox} combo This combo box
37458 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37459 * @param {Roo.form.ComboBox} combo This combo box
37460 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37466 if(this.transform){
37467 this.allowDomMove = false;
37468 var s = Roo.getDom(this.transform);
37469 if(!this.hiddenName){
37470 this.hiddenName = s.name;
37473 this.mode = 'local';
37474 var d = [], opts = s.options;
37475 for(var i = 0, len = opts.length;i < len; i++){
37477 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37479 this.value = value;
37481 d.push([value, o.text]);
37483 this.store = new Roo.data.SimpleStore({
37485 fields: ['value', 'text'],
37488 this.valueField = 'value';
37489 this.displayField = 'text';
37491 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37492 if(!this.lazyRender){
37493 this.target = true;
37494 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37495 s.parentNode.removeChild(s); // remove it
37496 this.render(this.el.parentNode);
37498 s.parentNode.removeChild(s); // remove it
37503 this.store = Roo.factory(this.store, Roo.data);
37506 this.selectedIndex = -1;
37507 if(this.mode == 'local'){
37508 if(config.queryDelay === undefined){
37509 this.queryDelay = 10;
37511 if(config.minChars === undefined){
37517 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37519 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37522 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37523 * rendering into an Roo.Editor, defaults to false)
37526 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37527 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37530 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37533 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37534 * the dropdown list (defaults to undefined, with no header element)
37538 * @cfg {String/Roo.Template} tpl The template to use to render the output
37542 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37544 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37546 listWidth: undefined,
37548 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37549 * mode = 'remote' or 'text' if mode = 'local')
37551 displayField: undefined,
37553 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37554 * mode = 'remote' or 'value' if mode = 'local').
37555 * Note: use of a valueField requires the user make a selection
37556 * in order for a value to be mapped.
37558 valueField: undefined,
37562 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37563 * field's data value (defaults to the underlying DOM element's name)
37565 hiddenName: undefined,
37567 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37571 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37573 selectedClass: 'x-combo-selected',
37575 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37576 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37577 * which displays a downward arrow icon).
37579 triggerClass : 'x-form-arrow-trigger',
37581 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37585 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37586 * anchor positions (defaults to 'tl-bl')
37588 listAlign: 'tl-bl?',
37590 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37594 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37595 * query specified by the allQuery config option (defaults to 'query')
37597 triggerAction: 'query',
37599 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37600 * (defaults to 4, does not apply if editable = false)
37604 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37605 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37609 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37610 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37614 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37615 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37619 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37620 * when editable = true (defaults to false)
37622 selectOnFocus:false,
37624 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37626 queryParam: 'query',
37628 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37629 * when mode = 'remote' (defaults to 'Loading...')
37631 loadingText: 'Loading...',
37633 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37637 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37641 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37642 * traditional select (defaults to true)
37646 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37650 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37654 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37655 * listWidth has a higher value)
37659 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37660 * allow the user to set arbitrary text into the field (defaults to false)
37662 forceSelection:false,
37664 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37665 * if typeAhead = true (defaults to 250)
37667 typeAheadDelay : 250,
37669 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37670 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37672 valueNotFoundText : undefined,
37674 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37676 blockFocus : false,
37679 * @cfg {Boolean} disableClear Disable showing of clear button.
37681 disableClear : false,
37683 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37685 alwaysQuery : false,
37691 // element that contains real text value.. (when hidden is used..)
37694 onRender : function(ct, position){
37695 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37696 if(this.hiddenName){
37697 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37699 this.hiddenField.value =
37700 this.hiddenValue !== undefined ? this.hiddenValue :
37701 this.value !== undefined ? this.value : '';
37703 // prevent input submission
37704 this.el.dom.removeAttribute('name');
37709 this.el.dom.setAttribute('autocomplete', 'off');
37712 var cls = 'x-combo-list';
37714 this.list = new Roo.Layer({
37715 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37718 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37719 this.list.setWidth(lw);
37720 this.list.swallowEvent('mousewheel');
37721 this.assetHeight = 0;
37724 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37725 this.assetHeight += this.header.getHeight();
37728 this.innerList = this.list.createChild({cls:cls+'-inner'});
37729 this.innerList.on('mouseover', this.onViewOver, this);
37730 this.innerList.on('mousemove', this.onViewMove, this);
37731 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37733 if(this.allowBlank && !this.pageSize && !this.disableClear){
37734 this.footer = this.list.createChild({cls:cls+'-ft'});
37735 this.pageTb = new Roo.Toolbar(this.footer);
37739 this.footer = this.list.createChild({cls:cls+'-ft'});
37740 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37741 {pageSize: this.pageSize});
37745 if (this.pageTb && this.allowBlank && !this.disableClear) {
37747 this.pageTb.add(new Roo.Toolbar.Fill(), {
37748 cls: 'x-btn-icon x-btn-clear',
37750 handler: function()
37753 _this.clearValue();
37754 _this.onSelect(false, -1);
37759 this.assetHeight += this.footer.getHeight();
37764 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37767 this.view = new Roo.View(this.innerList, this.tpl, {
37768 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37771 this.view.on('click', this.onViewClick, this);
37773 this.store.on('beforeload', this.onBeforeLoad, this);
37774 this.store.on('load', this.onLoad, this);
37775 this.store.on('loadexception', this.onLoadException, this);
37777 if(this.resizable){
37778 this.resizer = new Roo.Resizable(this.list, {
37779 pinned:true, handles:'se'
37781 this.resizer.on('resize', function(r, w, h){
37782 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37783 this.listWidth = w;
37784 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37785 this.restrictHeight();
37787 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37789 if(!this.editable){
37790 this.editable = true;
37791 this.setEditable(false);
37795 if (typeof(this.events.add.listeners) != 'undefined') {
37797 this.addicon = this.wrap.createChild(
37798 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37800 this.addicon.on('click', function(e) {
37801 this.fireEvent('add', this);
37804 if (typeof(this.events.edit.listeners) != 'undefined') {
37806 this.editicon = this.wrap.createChild(
37807 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37808 if (this.addicon) {
37809 this.editicon.setStyle('margin-left', '40px');
37811 this.editicon.on('click', function(e) {
37813 // we fire even if inothing is selected..
37814 this.fireEvent('edit', this, this.lastData );
37824 initEvents : function(){
37825 Roo.form.ComboBox.superclass.initEvents.call(this);
37827 this.keyNav = new Roo.KeyNav(this.el, {
37828 "up" : function(e){
37829 this.inKeyMode = true;
37833 "down" : function(e){
37834 if(!this.isExpanded()){
37835 this.onTriggerClick();
37837 this.inKeyMode = true;
37842 "enter" : function(e){
37843 this.onViewClick();
37847 "esc" : function(e){
37851 "tab" : function(e){
37852 this.onViewClick(false);
37853 this.fireEvent("specialkey", this, e);
37859 doRelay : function(foo, bar, hname){
37860 if(hname == 'down' || this.scope.isExpanded()){
37861 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37868 this.queryDelay = Math.max(this.queryDelay || 10,
37869 this.mode == 'local' ? 10 : 250);
37870 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37871 if(this.typeAhead){
37872 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37874 if(this.editable !== false){
37875 this.el.on("keyup", this.onKeyUp, this);
37877 if(this.forceSelection){
37878 this.on('blur', this.doForce, this);
37882 onDestroy : function(){
37884 this.view.setStore(null);
37885 this.view.el.removeAllListeners();
37886 this.view.el.remove();
37887 this.view.purgeListeners();
37890 this.list.destroy();
37893 this.store.un('beforeload', this.onBeforeLoad, this);
37894 this.store.un('load', this.onLoad, this);
37895 this.store.un('loadexception', this.onLoadException, this);
37897 Roo.form.ComboBox.superclass.onDestroy.call(this);
37901 fireKey : function(e){
37902 if(e.isNavKeyPress() && !this.list.isVisible()){
37903 this.fireEvent("specialkey", this, e);
37908 onResize: function(w, h){
37909 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37911 if(typeof w != 'number'){
37912 // we do not handle it!?!?
37915 var tw = this.trigger.getWidth();
37916 tw += this.addicon ? this.addicon.getWidth() : 0;
37917 tw += this.editicon ? this.editicon.getWidth() : 0;
37919 this.el.setWidth( this.adjustWidth('input', x));
37921 this.trigger.setStyle('left', x+'px');
37923 if(this.list && this.listWidth === undefined){
37924 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37925 this.list.setWidth(lw);
37926 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37934 * Allow or prevent the user from directly editing the field text. If false is passed,
37935 * the user will only be able to select from the items defined in the dropdown list. This method
37936 * is the runtime equivalent of setting the 'editable' config option at config time.
37937 * @param {Boolean} value True to allow the user to directly edit the field text
37939 setEditable : function(value){
37940 if(value == this.editable){
37943 this.editable = value;
37945 this.el.dom.setAttribute('readOnly', true);
37946 this.el.on('mousedown', this.onTriggerClick, this);
37947 this.el.addClass('x-combo-noedit');
37949 this.el.dom.setAttribute('readOnly', false);
37950 this.el.un('mousedown', this.onTriggerClick, this);
37951 this.el.removeClass('x-combo-noedit');
37956 onBeforeLoad : function(){
37957 if(!this.hasFocus){
37960 this.innerList.update(this.loadingText ?
37961 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37962 this.restrictHeight();
37963 this.selectedIndex = -1;
37967 onLoad : function(){
37968 if(!this.hasFocus){
37971 if(this.store.getCount() > 0){
37973 this.restrictHeight();
37974 if(this.lastQuery == this.allQuery){
37976 this.el.dom.select();
37978 if(!this.selectByValue(this.value, true)){
37979 this.select(0, true);
37983 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37984 this.taTask.delay(this.typeAheadDelay);
37988 this.onEmptyResults();
37993 onLoadException : function()
37996 Roo.log(this.store.reader.jsonData);
37997 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
37998 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
38004 onTypeAhead : function(){
38005 if(this.store.getCount() > 0){
38006 var r = this.store.getAt(0);
38007 var newValue = r.data[this.displayField];
38008 var len = newValue.length;
38009 var selStart = this.getRawValue().length;
38010 if(selStart != len){
38011 this.setRawValue(newValue);
38012 this.selectText(selStart, newValue.length);
38018 onSelect : function(record, index){
38019 if(this.fireEvent('beforeselect', this, record, index) !== false){
38020 this.setFromData(index > -1 ? record.data : false);
38022 this.fireEvent('select', this, record, index);
38027 * Returns the currently selected field value or empty string if no value is set.
38028 * @return {String} value The selected value
38030 getValue : function(){
38031 if(this.valueField){
38032 return typeof this.value != 'undefined' ? this.value : '';
38034 return Roo.form.ComboBox.superclass.getValue.call(this);
38039 * Clears any text/value currently set in the field
38041 clearValue : function(){
38042 if(this.hiddenField){
38043 this.hiddenField.value = '';
38046 this.setRawValue('');
38047 this.lastSelectionText = '';
38048 this.applyEmptyText();
38052 * Sets the specified value into the field. If the value finds a match, the corresponding record text
38053 * will be displayed in the field. If the value does not match the data value of an existing item,
38054 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
38055 * Otherwise the field will be blank (although the value will still be set).
38056 * @param {String} value The value to match
38058 setValue : function(v){
38060 if(this.valueField){
38061 var r = this.findRecord(this.valueField, v);
38063 text = r.data[this.displayField];
38064 }else if(this.valueNotFoundText !== undefined){
38065 text = this.valueNotFoundText;
38068 this.lastSelectionText = text;
38069 if(this.hiddenField){
38070 this.hiddenField.value = v;
38072 Roo.form.ComboBox.superclass.setValue.call(this, text);
38076 * @property {Object} the last set data for the element
38081 * Sets the value of the field based on a object which is related to the record format for the store.
38082 * @param {Object} value the value to set as. or false on reset?
38084 setFromData : function(o){
38085 var dv = ''; // display value
38086 var vv = ''; // value value..
38088 if (this.displayField) {
38089 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
38091 // this is an error condition!!!
38092 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
38095 if(this.valueField){
38096 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
38098 if(this.hiddenField){
38099 this.hiddenField.value = vv;
38101 this.lastSelectionText = dv;
38102 Roo.form.ComboBox.superclass.setValue.call(this, dv);
38106 // no hidden field.. - we store the value in 'value', but still display
38107 // display field!!!!
38108 this.lastSelectionText = dv;
38109 Roo.form.ComboBox.superclass.setValue.call(this, dv);
38115 reset : function(){
38116 // overridden so that last data is reset..
38117 this.setValue(this.originalValue);
38118 this.clearInvalid();
38119 this.lastData = false;
38122 findRecord : function(prop, value){
38124 if(this.store.getCount() > 0){
38125 this.store.each(function(r){
38126 if(r.data[prop] == value){
38136 getName: function()
38138 // returns hidden if it's set..
38139 if (!this.rendered) {return ''};
38140 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38144 onViewMove : function(e, t){
38145 this.inKeyMode = false;
38149 onViewOver : function(e, t){
38150 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38153 var item = this.view.findItemFromChild(t);
38155 var index = this.view.indexOf(item);
38156 this.select(index, false);
38161 onViewClick : function(doFocus)
38163 var index = this.view.getSelectedIndexes()[0];
38164 var r = this.store.getAt(index);
38166 this.onSelect(r, index);
38168 if(doFocus !== false && !this.blockFocus){
38174 restrictHeight : function(){
38175 this.innerList.dom.style.height = '';
38176 var inner = this.innerList.dom;
38177 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
38178 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
38179 this.list.beginUpdate();
38180 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
38181 this.list.alignTo(this.el, this.listAlign);
38182 this.list.endUpdate();
38186 onEmptyResults : function(){
38191 * Returns true if the dropdown list is expanded, else false.
38193 isExpanded : function(){
38194 return this.list.isVisible();
38198 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
38199 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38200 * @param {String} value The data value of the item to select
38201 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38202 * selected item if it is not currently in view (defaults to true)
38203 * @return {Boolean} True if the value matched an item in the list, else false
38205 selectByValue : function(v, scrollIntoView){
38206 if(v !== undefined && v !== null){
38207 var r = this.findRecord(this.valueField || this.displayField, v);
38209 this.select(this.store.indexOf(r), scrollIntoView);
38217 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
38218 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38219 * @param {Number} index The zero-based index of the list item to select
38220 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38221 * selected item if it is not currently in view (defaults to true)
38223 select : function(index, scrollIntoView){
38224 this.selectedIndex = index;
38225 this.view.select(index);
38226 if(scrollIntoView !== false){
38227 var el = this.view.getNode(index);
38229 this.innerList.scrollChildIntoView(el, false);
38235 selectNext : function(){
38236 var ct = this.store.getCount();
38238 if(this.selectedIndex == -1){
38240 }else if(this.selectedIndex < ct-1){
38241 this.select(this.selectedIndex+1);
38247 selectPrev : function(){
38248 var ct = this.store.getCount();
38250 if(this.selectedIndex == -1){
38252 }else if(this.selectedIndex != 0){
38253 this.select(this.selectedIndex-1);
38259 onKeyUp : function(e){
38260 if(this.editable !== false && !e.isSpecialKey()){
38261 this.lastKey = e.getKey();
38262 this.dqTask.delay(this.queryDelay);
38267 validateBlur : function(){
38268 return !this.list || !this.list.isVisible();
38272 initQuery : function(){
38273 this.doQuery(this.getRawValue());
38277 doForce : function(){
38278 if(this.el.dom.value.length > 0){
38279 this.el.dom.value =
38280 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
38281 this.applyEmptyText();
38286 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
38287 * query allowing the query action to be canceled if needed.
38288 * @param {String} query The SQL query to execute
38289 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38290 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
38291 * saved in the current store (defaults to false)
38293 doQuery : function(q, forceAll){
38294 if(q === undefined || q === null){
38299 forceAll: forceAll,
38303 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38307 forceAll = qe.forceAll;
38308 if(forceAll === true || (q.length >= this.minChars)){
38309 if(this.lastQuery != q || this.alwaysQuery){
38310 this.lastQuery = q;
38311 if(this.mode == 'local'){
38312 this.selectedIndex = -1;
38314 this.store.clearFilter();
38316 this.store.filter(this.displayField, q);
38320 this.store.baseParams[this.queryParam] = q;
38322 params: this.getParams(q)
38327 this.selectedIndex = -1;
38334 getParams : function(q){
38336 //p[this.queryParam] = q;
38339 p.limit = this.pageSize;
38345 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38347 collapse : function(){
38348 if(!this.isExpanded()){
38352 Roo.get(document).un('mousedown', this.collapseIf, this);
38353 Roo.get(document).un('mousewheel', this.collapseIf, this);
38354 if (!this.editable) {
38355 Roo.get(document).un('keydown', this.listKeyPress, this);
38357 this.fireEvent('collapse', this);
38361 collapseIf : function(e){
38362 if(!e.within(this.wrap) && !e.within(this.list)){
38368 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38370 expand : function(){
38371 if(this.isExpanded() || !this.hasFocus){
38374 this.list.alignTo(this.el, this.listAlign);
38376 Roo.get(document).on('mousedown', this.collapseIf, this);
38377 Roo.get(document).on('mousewheel', this.collapseIf, this);
38378 if (!this.editable) {
38379 Roo.get(document).on('keydown', this.listKeyPress, this);
38382 this.fireEvent('expand', this);
38386 // Implements the default empty TriggerField.onTriggerClick function
38387 onTriggerClick : function(){
38391 if(this.isExpanded()){
38393 if (!this.blockFocus) {
38398 this.hasFocus = true;
38399 if(this.triggerAction == 'all') {
38400 this.doQuery(this.allQuery, true);
38402 this.doQuery(this.getRawValue());
38404 if (!this.blockFocus) {
38409 listKeyPress : function(e)
38411 //Roo.log('listkeypress');
38412 // scroll to first matching element based on key pres..
38413 if (e.isSpecialKey()) {
38416 var k = String.fromCharCode(e.getKey()).toUpperCase();
38419 var csel = this.view.getSelectedNodes();
38420 var cselitem = false;
38422 var ix = this.view.indexOf(csel[0]);
38423 cselitem = this.store.getAt(ix);
38424 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38430 this.store.each(function(v) {
38432 // start at existing selection.
38433 if (cselitem.id == v.id) {
38439 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38440 match = this.store.indexOf(v);
38445 if (match === false) {
38446 return true; // no more action?
38449 this.view.select(match);
38450 var sn = Roo.get(this.view.getSelectedNodes()[0])
38451 sn.scrollIntoView(sn.dom.parentNode, false);
38455 * @cfg {Boolean} grow
38459 * @cfg {Number} growMin
38463 * @cfg {Number} growMax
38471 * Copyright(c) 2010-2012, Roo J Solutions Limited
38478 * @class Roo.form.ComboBoxArray
38479 * @extends Roo.form.TextField
38480 * A facebook style adder... for lists of email / people / countries etc...
38481 * pick multiple items from a combo box, and shows each one.
38483 * Fred [x] Brian [x] [Pick another |v]
38486 * For this to work: it needs various extra information
38487 * - normal combo problay has
38489 * + displayField, valueField
38491 * For our purpose...
38494 * If we change from 'extends' to wrapping...
38501 * Create a new ComboBoxArray.
38502 * @param {Object} config Configuration options
38506 Roo.form.ComboBoxArray = function(config)
38509 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
38511 this.items = new Roo.util.MixedCollection(false);
38513 // construct the child combo...
38523 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
38526 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
38531 // behavies liek a hiddne field
38532 inputType: 'hidden',
38534 * @cfg {Number} width The width of the box that displays the selected element
38541 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
38545 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
38547 hiddenName : false,
38550 // private the array of items that are displayed..
38552 // private - the hidden field el.
38554 // private - the filed el..
38557 //validateValue : function() { return true; }, // all values are ok!
38558 //onAddClick: function() { },
38560 onRender : function(ct, position)
38563 // create the standard hidden element
38564 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
38567 // give fake names to child combo;
38568 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
38569 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
38571 this.combo = Roo.factory(this.combo, Roo.form);
38572 this.combo.onRender(ct, position);
38574 // assigned so form know we need to do this..
38575 this.store = this.combo.store;
38576 this.valueField = this.combo.valueField;
38577 this.displayField = this.combo.displayField ;
38580 this.combo.wrap.addClass('x-cbarray-grp');
38582 var cbwrap = this.combo.wrap.createChild(
38583 {tag: 'div', cls: 'x-cbarray-cb'},
38588 this.hiddenEl = this.combo.wrap.createChild({
38589 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
38591 this.el = this.combo.wrap.createChild({
38592 tag: 'input', type:'hidden' , name: this.name, value : ''
38594 // this.el.dom.removeAttribute("name");
38597 this.outerWrap = this.combo.wrap;
38598 this.wrap = cbwrap;
38600 this.outerWrap.setWidth(this.width);
38601 this.outerWrap.dom.removeChild(this.el.dom);
38603 this.wrap.dom.appendChild(this.el.dom);
38604 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
38605 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
38607 this.combo.trigger.setStyle('position','relative');
38608 this.combo.trigger.setStyle('left', '0px');
38609 this.combo.trigger.setStyle('top', '2px');
38611 this.combo.el.setStyle('vertical-align', 'text-bottom');
38613 //this.trigger.setStyle('vertical-align', 'top');
38615 // this should use the code from combo really... on('add' ....)
38619 this.adder = this.outerWrap.createChild(
38620 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
38622 this.adder.on('click', function(e) {
38623 _t.fireEvent('adderclick', this, e);
38627 //this.adder.on('click', this.onAddClick, _t);
38630 this.combo.on('select', function(cb, rec, ix) {
38631 this.addItem(rec.data);
38634 cb.el.dom.value = '';
38635 //cb.lastData = rec.data;
38644 getName: function()
38646 // returns hidden if it's set..
38647 if (!this.rendered) {return ''};
38648 return this.hiddenName ? this.hiddenName : this.name;
38653 onResize: function(w, h){
38656 // not sure if this is needed..
38657 //this.combo.onResize(w,h);
38659 if(typeof w != 'number'){
38660 // we do not handle it!?!?
38663 var tw = this.combo.trigger.getWidth();
38664 tw += this.addicon ? this.addicon.getWidth() : 0;
38665 tw += this.editicon ? this.editicon.getWidth() : 0;
38667 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
38669 this.combo.trigger.setStyle('left', '0px');
38671 if(this.list && this.listWidth === undefined){
38672 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
38673 this.list.setWidth(lw);
38674 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38681 addItem: function(rec)
38683 var valueField = this.combo.valueField;
38684 var displayField = this.combo.displayField;
38685 if (this.items.indexOfKey(rec[valueField]) > -1) {
38686 //console.log("GOT " + rec.data.id);
38690 var x = new Roo.form.ComboBoxArray.Item({
38691 //id : rec[this.idField],
38693 displayField : displayField ,
38694 tipField : displayField ,
38698 this.items.add(rec[valueField],x);
38699 // add it before the element..
38700 this.updateHiddenEl();
38701 x.render(this.outerWrap, this.wrap.dom);
38702 // add the image handler..
38705 updateHiddenEl : function()
38708 if (!this.hiddenEl) {
38712 var idField = this.combo.valueField;
38714 this.items.each(function(f) {
38715 ar.push(f.data[idField]);
38718 this.hiddenEl.dom.value = ar.join(',');
38724 //Roo.form.ComboBoxArray.superclass.reset.call(this);
38725 this.items.each(function(f) {
38728 this.el.dom.value = '';
38729 if (this.hiddenEl) {
38730 this.hiddenEl.dom.value = '';
38734 getValue: function()
38736 return this.hiddenEl ? this.hiddenEl.dom.value : '';
38738 setValue: function(v) // not a valid action - must use addItems..
38745 if (this.store.isLocal && (typeof(v) == 'string')) {
38746 // then we can use the store to find the values..
38747 // comma seperated at present.. this needs to allow JSON based encoding..
38748 this.hiddenEl.value = v;
38750 Roo.each(v.split(','), function(k) {
38751 Roo.log("CHECK " + this.valueField + ',' + k);
38752 var li = this.store.query(this.valueField, k);
38757 add[this.valueField] = k;
38758 add[this.displayField] = li.item(0).data[this.displayField];
38766 if (typeof(v) == 'object') {
38767 // then let's assume it's an array of objects..
38768 Roo.each(v, function(l) {
38776 setFromData: function(v)
38778 // this recieves an object, if setValues is called.
38780 this.el.dom.value = v[this.displayField];
38781 this.hiddenEl.dom.value = v[this.valueField];
38782 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
38785 var keys = v[this.valueField].split(',');
38786 var display = v[this.displayField].split(',');
38787 for (var i = 0 ; i < keys.length; i++) {
38790 add[this.valueField] = keys[i];
38791 add[this.displayField] = display[i];
38799 validateValue : function(value){
38800 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
38809 * @class Roo.form.ComboBoxArray.Item
38810 * @extends Roo.BoxComponent
38811 * A selected item in the list
38812 * Fred [x] Brian [x] [Pick another |v]
38815 * Create a new item.
38816 * @param {Object} config Configuration options
38819 Roo.form.ComboBoxArray.Item = function(config) {
38820 config.id = Roo.id();
38821 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
38824 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
38827 displayField : false,
38831 defaultAutoCreate : {
38833 cls: 'x-cbarray-item',
38840 src : Roo.BLANK_IMAGE_URL ,
38848 onRender : function(ct, position)
38850 Roo.form.Field.superclass.onRender.call(this, ct, position);
38853 var cfg = this.getAutoCreate();
38854 this.el = ct.createChild(cfg, position);
38857 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
38859 this.el.child('div').dom.innerHTML = this.cb.renderer ?
38860 this.cb.renderer(this.data) :
38861 String.format('{0}',this.data[this.displayField]);
38864 this.el.child('div').dom.setAttribute('qtip',
38865 String.format('{0}',this.data[this.tipField])
38868 this.el.child('img').on('click', this.remove, this);
38872 remove : function()
38875 this.cb.items.remove(this);
38876 this.el.child('img').un('click', this.remove, this);
38878 this.cb.updateHiddenEl();
38884 * Ext JS Library 1.1.1
38885 * Copyright(c) 2006-2007, Ext JS, LLC.
38887 * Originally Released Under LGPL - original licence link has changed is not relivant.
38890 * <script type="text/javascript">
38893 * @class Roo.form.Checkbox
38894 * @extends Roo.form.Field
38895 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38897 * Creates a new Checkbox
38898 * @param {Object} config Configuration options
38900 Roo.form.Checkbox = function(config){
38901 Roo.form.Checkbox.superclass.constructor.call(this, config);
38905 * Fires when the checkbox is checked or unchecked.
38906 * @param {Roo.form.Checkbox} this This checkbox
38907 * @param {Boolean} checked The new checked value
38913 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38915 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38917 focusClass : undefined,
38919 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38921 fieldClass: "x-form-field",
38923 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38927 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38928 * {tag: "input", type: "checkbox", autocomplete: "off"})
38930 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38932 * @cfg {String} boxLabel The text that appears beside the checkbox
38936 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38940 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38942 valueOff: '0', // value when not checked..
38944 actionMode : 'viewEl',
38947 itemCls : 'x-menu-check-item x-form-item',
38948 groupClass : 'x-menu-group-item',
38949 inputType : 'hidden',
38952 inSetChecked: false, // check that we are not calling self...
38954 inputElement: false, // real input element?
38955 basedOn: false, // ????
38957 isFormField: true, // not sure where this is needed!!!!
38959 onResize : function(){
38960 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38961 if(!this.boxLabel){
38962 this.el.alignTo(this.wrap, 'c-c');
38966 initEvents : function(){
38967 Roo.form.Checkbox.superclass.initEvents.call(this);
38968 this.el.on("click", this.onClick, this);
38969 this.el.on("change", this.onClick, this);
38973 getResizeEl : function(){
38977 getPositionEl : function(){
38982 onRender : function(ct, position){
38983 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38985 if(this.inputValue !== undefined){
38986 this.el.dom.value = this.inputValue;
38989 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38990 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38991 var viewEl = this.wrap.createChild({
38992 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38993 this.viewEl = viewEl;
38994 this.wrap.on('click', this.onClick, this);
38996 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38997 this.el.on('propertychange', this.setFromHidden, this); //ie
39002 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
39003 // viewEl.on('click', this.onClick, this);
39005 //if(this.checked){
39006 this.setChecked(this.checked);
39008 //this.checked = this.el.dom;
39014 initValue : Roo.emptyFn,
39017 * Returns the checked state of the checkbox.
39018 * @return {Boolean} True if checked, else false
39020 getValue : function(){
39022 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
39024 return this.valueOff;
39029 onClick : function(){
39030 this.setChecked(!this.checked);
39032 //if(this.el.dom.checked != this.checked){
39033 // this.setValue(this.el.dom.checked);
39038 * Sets the checked state of the checkbox.
39039 * On is always based on a string comparison between inputValue and the param.
39040 * @param {Boolean/String} value - the value to set
39041 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
39043 setValue : function(v,suppressEvent){
39046 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
39047 //if(this.el && this.el.dom){
39048 // this.el.dom.checked = this.checked;
39049 // this.el.dom.defaultChecked = this.checked;
39051 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
39052 //this.fireEvent("check", this, this.checked);
39055 setChecked : function(state,suppressEvent)
39057 if (this.inSetChecked) {
39058 this.checked = state;
39064 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
39066 this.checked = state;
39067 if(suppressEvent !== true){
39068 this.fireEvent('check', this, state);
39070 this.inSetChecked = true;
39071 this.el.dom.value = state ? this.inputValue : this.valueOff;
39072 this.inSetChecked = false;
39075 // handle setting of hidden value by some other method!!?!?
39076 setFromHidden: function()
39081 //console.log("SET FROM HIDDEN");
39082 //alert('setFrom hidden');
39083 this.setValue(this.el.dom.value);
39086 onDestroy : function()
39089 Roo.get(this.viewEl).remove();
39092 Roo.form.Checkbox.superclass.onDestroy.call(this);
39097 * Ext JS Library 1.1.1
39098 * Copyright(c) 2006-2007, Ext JS, LLC.
39100 * Originally Released Under LGPL - original licence link has changed is not relivant.
39103 * <script type="text/javascript">
39107 * @class Roo.form.Radio
39108 * @extends Roo.form.Checkbox
39109 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
39110 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
39112 * Creates a new Radio
39113 * @param {Object} config Configuration options
39115 Roo.form.Radio = function(){
39116 Roo.form.Radio.superclass.constructor.apply(this, arguments);
39118 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
39119 inputType: 'radio',
39122 * If this radio is part of a group, it will return the selected value
39125 getGroupValue : function(){
39126 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
39128 });//<script type="text/javascript">
39131 * Ext JS Library 1.1.1
39132 * Copyright(c) 2006-2007, Ext JS, LLC.
39133 * licensing@extjs.com
39135 * http://www.extjs.com/license
39141 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
39142 * - IE ? - no idea how much works there.
39150 * @class Ext.form.HtmlEditor
39151 * @extends Ext.form.Field
39152 * Provides a lightweight HTML Editor component.
39154 * This has been tested on Fireforx / Chrome.. IE may not be so great..
39156 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
39157 * supported by this editor.</b><br/><br/>
39158 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
39159 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
39161 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
39163 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
39167 * @cfg {String} createLinkText The default text for the create link prompt
39169 createLinkText : 'Please enter the URL for the link:',
39171 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
39173 defaultLinkValue : 'http:/'+'/',
39176 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
39181 * @cfg {Number} height (in pixels)
39185 * @cfg {Number} width (in pixels)
39190 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
39193 stylesheets: false,
39198 // private properties
39199 validationEvent : false,
39201 initialized : false,
39203 sourceEditMode : false,
39204 onFocus : Roo.emptyFn,
39206 hideMode:'offsets',
39208 defaultAutoCreate : { // modified by initCompnoent..
39210 style:"width:500px;height:300px;",
39211 autocomplete: "off"
39215 initComponent : function(){
39218 * @event initialize
39219 * Fires when the editor is fully initialized (including the iframe)
39220 * @param {HtmlEditor} this
39225 * Fires when the editor is first receives the focus. Any insertion must wait
39226 * until after this event.
39227 * @param {HtmlEditor} this
39231 * @event beforesync
39232 * Fires before the textarea is updated with content from the editor iframe. Return false
39233 * to cancel the sync.
39234 * @param {HtmlEditor} this
39235 * @param {String} html
39239 * @event beforepush
39240 * Fires before the iframe editor is updated with content from the textarea. Return false
39241 * to cancel the push.
39242 * @param {HtmlEditor} this
39243 * @param {String} html
39248 * Fires when the textarea is updated with content from the editor iframe.
39249 * @param {HtmlEditor} this
39250 * @param {String} html
39255 * Fires when the iframe editor is updated with content from the textarea.
39256 * @param {HtmlEditor} this
39257 * @param {String} html
39261 * @event editmodechange
39262 * Fires when the editor switches edit modes
39263 * @param {HtmlEditor} this
39264 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
39266 editmodechange: true,
39268 * @event editorevent
39269 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
39270 * @param {HtmlEditor} this
39274 this.defaultAutoCreate = {
39276 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
39277 autocomplete: "off"
39282 * Protected method that will not generally be called directly. It
39283 * is called when the editor creates its toolbar. Override this method if you need to
39284 * add custom toolbar buttons.
39285 * @param {HtmlEditor} editor
39287 createToolbar : function(editor){
39288 if (!editor.toolbars || !editor.toolbars.length) {
39289 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
39292 for (var i =0 ; i < editor.toolbars.length;i++) {
39293 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
39294 editor.toolbars[i].init(editor);
39301 * Protected method that will not generally be called directly. It
39302 * is called when the editor initializes the iframe with HTML contents. Override this method if you
39303 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
39305 getDocMarkup : function(){
39308 if (this.stylesheets === false) {
39310 Roo.get(document.head).select('style').each(function(node) {
39311 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
39314 Roo.get(document.head).select('link').each(function(node) {
39315 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
39318 } else if (!this.stylesheets.length) {
39320 st = '<style type="text/css">' +
39321 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
39324 Roo.each(this.stylesheets, function(s) {
39325 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
39330 st += '<style type="text/css">' +
39331 'IMG { cursor: pointer } ' +
39335 return '<html><head>' + st +
39336 //<style type="text/css">' +
39337 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
39339 ' </head><body class="roo-htmleditor-body"></body></html>';
39343 onRender : function(ct, position)
39346 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
39347 this.el.dom.style.border = '0 none';
39348 this.el.dom.setAttribute('tabIndex', -1);
39349 this.el.addClass('x-hidden');
39350 if(Roo.isIE){ // fix IE 1px bogus margin
39351 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
39353 this.wrap = this.el.wrap({
39354 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
39357 if (this.resizable) {
39358 this.resizeEl = new Roo.Resizable(this.wrap, {
39362 minHeight : this.height,
39363 height: this.height,
39364 handles : this.resizable,
39367 resize : function(r, w, h) {
39368 _t.onResize(w,h); // -something
39375 this.frameId = Roo.id();
39377 this.createToolbar(this);
39381 var iframe = this.wrap.createChild({
39384 name: this.frameId,
39385 frameBorder : 'no',
39386 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
39390 // console.log(iframe);
39391 //this.wrap.dom.appendChild(iframe);
39393 this.iframe = iframe.dom;
39395 this.assignDocWin();
39397 this.doc.designMode = 'on';
39400 this.doc.write(this.getDocMarkup());
39404 var task = { // must defer to wait for browser to be ready
39406 //console.log("run task?" + this.doc.readyState);
39407 this.assignDocWin();
39408 if(this.doc.body || this.doc.readyState == 'complete'){
39410 this.doc.designMode="on";
39414 Roo.TaskMgr.stop(task);
39415 this.initEditor.defer(10, this);
39422 Roo.TaskMgr.start(task);
39425 this.setSize(this.wrap.getSize());
39427 if (this.resizeEl) {
39428 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
39429 // should trigger onReize..
39434 onResize : function(w, h)
39436 //Roo.log('resize: ' +w + ',' + h );
39437 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
39438 if(this.el && this.iframe){
39439 if(typeof w == 'number'){
39440 var aw = w - this.wrap.getFrameWidth('lr');
39441 this.el.setWidth(this.adjustWidth('textarea', aw));
39442 this.iframe.style.width = aw + 'px';
39444 if(typeof h == 'number'){
39446 for (var i =0; i < this.toolbars.length;i++) {
39447 // fixme - ask toolbars for heights?
39448 tbh += this.toolbars[i].tb.el.getHeight();
39449 if (this.toolbars[i].footer) {
39450 tbh += this.toolbars[i].footer.el.getHeight();
39457 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
39458 ah -= 5; // knock a few pixes off for look..
39459 this.el.setHeight(this.adjustWidth('textarea', ah));
39460 this.iframe.style.height = ah + 'px';
39462 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
39469 * Toggles the editor between standard and source edit mode.
39470 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
39472 toggleSourceEdit : function(sourceEditMode){
39474 this.sourceEditMode = sourceEditMode === true;
39476 if(this.sourceEditMode){
39479 this.iframe.className = 'x-hidden';
39480 this.el.removeClass('x-hidden');
39481 this.el.dom.removeAttribute('tabIndex');
39486 this.iframe.className = '';
39487 this.el.addClass('x-hidden');
39488 this.el.dom.setAttribute('tabIndex', -1);
39491 this.setSize(this.wrap.getSize());
39492 this.fireEvent('editmodechange', this, this.sourceEditMode);
39495 // private used internally
39496 createLink : function(){
39497 var url = prompt(this.createLinkText, this.defaultLinkValue);
39498 if(url && url != 'http:/'+'/'){
39499 this.relayCmd('createlink', url);
39503 // private (for BoxComponent)
39504 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39506 // private (for BoxComponent)
39507 getResizeEl : function(){
39511 // private (for BoxComponent)
39512 getPositionEl : function(){
39517 initEvents : function(){
39518 this.originalValue = this.getValue();
39522 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
39525 markInvalid : Roo.emptyFn,
39527 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
39530 clearInvalid : Roo.emptyFn,
39532 setValue : function(v){
39533 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
39538 * Protected method that will not generally be called directly. If you need/want
39539 * custom HTML cleanup, this is the method you should override.
39540 * @param {String} html The HTML to be cleaned
39541 * return {String} The cleaned HTML
39543 cleanHtml : function(html){
39544 html = String(html);
39545 if(html.length > 5){
39546 if(Roo.isSafari){ // strip safari nonsense
39547 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
39550 if(html == ' '){
39557 * Protected method that will not generally be called directly. Syncs the contents
39558 * of the editor iframe with the textarea.
39560 syncValue : function(){
39561 if(this.initialized){
39562 var bd = (this.doc.body || this.doc.documentElement);
39563 //this.cleanUpPaste(); -- this is done else where and causes havoc..
39564 var html = bd.innerHTML;
39566 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
39567 var m = bs.match(/text-align:(.*?);/i);
39569 html = '<div style="'+m[0]+'">' + html + '</div>';
39572 html = this.cleanHtml(html);
39573 // fix up the special chars..
39574 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
39575 return "&#"+b.charCodeAt()+";"
39577 if(this.fireEvent('beforesync', this, html) !== false){
39578 this.el.dom.value = html;
39579 this.fireEvent('sync', this, html);
39585 * Protected method that will not generally be called directly. Pushes the value of the textarea
39586 * into the iframe editor.
39588 pushValue : function(){
39589 if(this.initialized){
39590 var v = this.el.dom.value;
39595 if(this.fireEvent('beforepush', this, v) !== false){
39596 var d = (this.doc.body || this.doc.documentElement);
39598 this.cleanUpPaste();
39599 this.el.dom.value = d.innerHTML;
39600 this.fireEvent('push', this, v);
39606 deferFocus : function(){
39607 this.focus.defer(10, this);
39611 focus : function(){
39612 if(this.win && !this.sourceEditMode){
39619 assignDocWin: function()
39621 var iframe = this.iframe;
39624 this.doc = iframe.contentWindow.document;
39625 this.win = iframe.contentWindow;
39627 if (!Roo.get(this.frameId)) {
39630 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
39631 this.win = Roo.get(this.frameId).dom.contentWindow;
39636 initEditor : function(){
39637 //console.log("INIT EDITOR");
39638 this.assignDocWin();
39642 this.doc.designMode="on";
39644 this.doc.write(this.getDocMarkup());
39647 var dbody = (this.doc.body || this.doc.documentElement);
39648 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
39649 // this copies styles from the containing element into thsi one..
39650 // not sure why we need all of this..
39651 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
39652 ss['background-attachment'] = 'fixed'; // w3c
39653 dbody.bgProperties = 'fixed'; // ie
39654 Roo.DomHelper.applyStyles(dbody, ss);
39655 Roo.EventManager.on(this.doc, {
39656 //'mousedown': this.onEditorEvent,
39657 'mouseup': this.onEditorEvent,
39658 'dblclick': this.onEditorEvent,
39659 'click': this.onEditorEvent,
39660 'keyup': this.onEditorEvent,
39665 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
39667 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
39668 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
39670 this.initialized = true;
39672 this.fireEvent('initialize', this);
39677 onDestroy : function(){
39683 for (var i =0; i < this.toolbars.length;i++) {
39684 // fixme - ask toolbars for heights?
39685 this.toolbars[i].onDestroy();
39688 this.wrap.dom.innerHTML = '';
39689 this.wrap.remove();
39694 onFirstFocus : function(){
39696 this.assignDocWin();
39699 this.activated = true;
39700 for (var i =0; i < this.toolbars.length;i++) {
39701 this.toolbars[i].onFirstFocus();
39704 if(Roo.isGecko){ // prevent silly gecko errors
39706 var s = this.win.getSelection();
39707 if(!s.focusNode || s.focusNode.nodeType != 3){
39708 var r = s.getRangeAt(0);
39709 r.selectNodeContents((this.doc.body || this.doc.documentElement));
39714 this.execCmd('useCSS', true);
39715 this.execCmd('styleWithCSS', false);
39718 this.fireEvent('activate', this);
39722 adjustFont: function(btn){
39723 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
39724 //if(Roo.isSafari){ // safari
39727 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
39728 if(Roo.isSafari){ // safari
39729 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
39730 v = (v < 10) ? 10 : v;
39731 v = (v > 48) ? 48 : v;
39732 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
39737 v = Math.max(1, v+adjust);
39739 this.execCmd('FontSize', v );
39742 onEditorEvent : function(e){
39743 this.fireEvent('editorevent', this, e);
39744 // this.updateToolbar();
39745 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
39748 insertTag : function(tg)
39750 // could be a bit smarter... -> wrap the current selected tRoo..
39752 this.execCmd("formatblock", tg);
39756 insertText : function(txt)
39760 range = this.createRange();
39761 range.deleteContents();
39762 //alert(Sender.getAttribute('label'));
39764 range.insertNode(this.doc.createTextNode(txt));
39768 relayBtnCmd : function(btn){
39769 this.relayCmd(btn.cmd);
39773 * Executes a Midas editor command on the editor document and performs necessary focus and
39774 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
39775 * @param {String} cmd The Midas command
39776 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39778 relayCmd : function(cmd, value){
39780 this.execCmd(cmd, value);
39781 this.fireEvent('editorevent', this);
39782 //this.updateToolbar();
39787 * Executes a Midas editor command directly on the editor document.
39788 * For visual commands, you should use {@link #relayCmd} instead.
39789 * <b>This should only be called after the editor is initialized.</b>
39790 * @param {String} cmd The Midas command
39791 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39793 execCmd : function(cmd, value){
39794 this.doc.execCommand(cmd, false, value === undefined ? null : value);
39801 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
39803 * @param {String} text | dom node..
39805 insertAtCursor : function(text)
39810 if(!this.activated){
39816 var r = this.doc.selection.createRange();
39827 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
39831 // from jquery ui (MIT licenced)
39833 var win = this.win;
39835 if (win.getSelection && win.getSelection().getRangeAt) {
39836 range = win.getSelection().getRangeAt(0);
39837 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
39838 range.insertNode(node);
39839 } else if (win.document.selection && win.document.selection.createRange) {
39840 // no firefox support
39841 var txt = typeof(text) == 'string' ? text : text.outerHTML;
39842 win.document.selection.createRange().pasteHTML(txt);
39844 // no firefox support
39845 var txt = typeof(text) == 'string' ? text : text.outerHTML;
39846 this.execCmd('InsertHTML', txt);
39855 mozKeyPress : function(e){
39857 var c = e.getCharCode(), cmd;
39860 c = String.fromCharCode(c).toLowerCase();
39874 this.cleanUpPaste.defer(100, this);
39882 e.preventDefault();
39890 fixKeys : function(){ // load time branching for fastest keydown performance
39892 return function(e){
39893 var k = e.getKey(), r;
39896 r = this.doc.selection.createRange();
39899 r.pasteHTML('    ');
39906 r = this.doc.selection.createRange();
39908 var target = r.parentElement();
39909 if(!target || target.tagName.toLowerCase() != 'li'){
39911 r.pasteHTML('<br />');
39917 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39918 this.cleanUpPaste.defer(100, this);
39924 }else if(Roo.isOpera){
39925 return function(e){
39926 var k = e.getKey();
39930 this.execCmd('InsertHTML','    ');
39933 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39934 this.cleanUpPaste.defer(100, this);
39939 }else if(Roo.isSafari){
39940 return function(e){
39941 var k = e.getKey();
39945 this.execCmd('InsertText','\t');
39949 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39950 this.cleanUpPaste.defer(100, this);
39958 getAllAncestors: function()
39960 var p = this.getSelectedNode();
39963 a.push(p); // push blank onto stack..
39964 p = this.getParentElement();
39968 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39972 a.push(this.doc.body);
39976 lastSelNode : false,
39979 getSelection : function()
39981 this.assignDocWin();
39982 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39985 getSelectedNode: function()
39987 // this may only work on Gecko!!!
39989 // should we cache this!!!!
39994 var range = this.createRange(this.getSelection()).cloneRange();
39997 var parent = range.parentElement();
39999 var testRange = range.duplicate();
40000 testRange.moveToElementText(parent);
40001 if (testRange.inRange(range)) {
40004 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
40007 parent = parent.parentElement;
40012 // is ancestor a text element.
40013 var ac = range.commonAncestorContainer;
40014 if (ac.nodeType == 3) {
40015 ac = ac.parentNode;
40018 var ar = ac.childNodes;
40021 var other_nodes = [];
40022 var has_other_nodes = false;
40023 for (var i=0;i<ar.length;i++) {
40024 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
40027 // fullly contained node.
40029 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
40034 // probably selected..
40035 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
40036 other_nodes.push(ar[i]);
40040 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
40045 has_other_nodes = true;
40047 if (!nodes.length && other_nodes.length) {
40048 nodes= other_nodes;
40050 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
40056 createRange: function(sel)
40058 // this has strange effects when using with
40059 // top toolbar - not sure if it's a great idea.
40060 //this.editor.contentWindow.focus();
40061 if (typeof sel != "undefined") {
40063 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
40065 return this.doc.createRange();
40068 return this.doc.createRange();
40071 getParentElement: function()
40074 this.assignDocWin();
40075 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
40077 var range = this.createRange(sel);
40080 var p = range.commonAncestorContainer;
40081 while (p.nodeType == 3) { // text node
40092 * Range intersection.. the hard stuff...
40096 * [ -- selected range --- ]
40100 * if end is before start or hits it. fail.
40101 * if start is after end or hits it fail.
40103 * if either hits (but other is outside. - then it's not
40109 // @see http://www.thismuchiknow.co.uk/?p=64.
40110 rangeIntersectsNode : function(range, node)
40112 var nodeRange = node.ownerDocument.createRange();
40114 nodeRange.selectNode(node);
40116 nodeRange.selectNodeContents(node);
40119 var rangeStartRange = range.cloneRange();
40120 rangeStartRange.collapse(true);
40122 var rangeEndRange = range.cloneRange();
40123 rangeEndRange.collapse(false);
40125 var nodeStartRange = nodeRange.cloneRange();
40126 nodeStartRange.collapse(true);
40128 var nodeEndRange = nodeRange.cloneRange();
40129 nodeEndRange.collapse(false);
40131 return rangeStartRange.compareBoundaryPoints(
40132 Range.START_TO_START, nodeEndRange) == -1 &&
40133 rangeEndRange.compareBoundaryPoints(
40134 Range.START_TO_START, nodeStartRange) == 1;
40138 rangeCompareNode : function(range, node)
40140 var nodeRange = node.ownerDocument.createRange();
40142 nodeRange.selectNode(node);
40144 nodeRange.selectNodeContents(node);
40148 range.collapse(true);
40150 nodeRange.collapse(true);
40152 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
40153 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
40155 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
40157 var nodeIsBefore = ss == 1;
40158 var nodeIsAfter = ee == -1;
40160 if (nodeIsBefore && nodeIsAfter)
40162 if (!nodeIsBefore && nodeIsAfter)
40163 return 1; //right trailed.
40165 if (nodeIsBefore && !nodeIsAfter)
40166 return 2; // left trailed.
40171 // private? - in a new class?
40172 cleanUpPaste : function()
40174 // cleans up the whole document..
40175 Roo.log('cleanuppaste');
40176 this.cleanUpChildren(this.doc.body);
40177 var clean = this.cleanWordChars(this.doc.body.innerHTML);
40178 if (clean != this.doc.body.innerHTML) {
40179 this.doc.body.innerHTML = clean;
40184 cleanWordChars : function(input) {
40185 var he = Roo.form.HtmlEditor;
40187 var output = input;
40188 Roo.each(he.swapCodes, function(sw) {
40190 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
40191 output = output.replace(swapper, sw[1]);
40197 cleanUpChildren : function (n)
40199 if (!n.childNodes.length) {
40202 for (var i = n.childNodes.length-1; i > -1 ; i--) {
40203 this.cleanUpChild(n.childNodes[i]);
40210 cleanUpChild : function (node)
40212 //console.log(node);
40213 if (node.nodeName == "#text") {
40214 // clean up silly Windows -- stuff?
40217 if (node.nodeName == "#comment") {
40218 node.parentNode.removeChild(node);
40219 // clean up silly Windows -- stuff?
40223 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
40225 node.parentNode.removeChild(node);
40230 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
40232 // remove <a name=....> as rendering on yahoo mailer is bored with this.
40234 if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
40235 remove_keep_children = true;
40238 if (remove_keep_children) {
40239 this.cleanUpChildren(node);
40240 // inserts everything just before this node...
40241 while (node.childNodes.length) {
40242 var cn = node.childNodes[0];
40243 node.removeChild(cn);
40244 node.parentNode.insertBefore(cn, node);
40246 node.parentNode.removeChild(node);
40250 if (!node.attributes || !node.attributes.length) {
40251 this.cleanUpChildren(node);
40255 function cleanAttr(n,v)
40258 if (v.match(/^\./) || v.match(/^\//)) {
40261 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
40264 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
40265 node.removeAttribute(n);
40269 function cleanStyle(n,v)
40271 if (v.match(/expression/)) { //XSS?? should we even bother..
40272 node.removeAttribute(n);
40277 var parts = v.split(/;/);
40278 Roo.each(parts, function(p) {
40279 p = p.replace(/\s+/g,'');
40283 var l = p.split(':').shift().replace(/\s+/g,'');
40285 // only allow 'c whitelisted system attributes'
40286 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
40287 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
40288 node.removeAttribute(n);
40298 for (var i = node.attributes.length-1; i > -1 ; i--) {
40299 var a = node.attributes[i];
40301 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
40302 node.removeAttribute(a.name);
40305 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
40306 cleanAttr(a.name,a.value); // fixme..
40309 if (a.name == 'style') {
40310 cleanStyle(a.name,a.value);
40312 /// clean up MS crap..
40313 // tecnically this should be a list of valid class'es..
40316 if (a.name == 'class') {
40317 if (a.value.match(/^Mso/)) {
40318 node.className = '';
40321 if (a.value.match(/body/)) {
40322 node.className = '';
40332 this.cleanUpChildren(node);
40338 // hide stuff that is not compatible
40352 * @event specialkey
40356 * @cfg {String} fieldClass @hide
40359 * @cfg {String} focusClass @hide
40362 * @cfg {String} autoCreate @hide
40365 * @cfg {String} inputType @hide
40368 * @cfg {String} invalidClass @hide
40371 * @cfg {String} invalidText @hide
40374 * @cfg {String} msgFx @hide
40377 * @cfg {String} validateOnBlur @hide
40381 Roo.form.HtmlEditor.white = [
40382 'area', 'br', 'img', 'input', 'hr', 'wbr',
40384 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
40385 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
40386 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
40387 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
40388 'table', 'ul', 'xmp',
40390 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
40393 'dir', 'menu', 'ol', 'ul', 'dl',
40399 Roo.form.HtmlEditor.black = [
40400 // 'embed', 'object', // enable - backend responsiblity to clean thiese
40402 'base', 'basefont', 'bgsound', 'blink', 'body',
40403 'frame', 'frameset', 'head', 'html', 'ilayer',
40404 'iframe', 'layer', 'link', 'meta', 'object',
40405 'script', 'style' ,'title', 'xml' // clean later..
40407 Roo.form.HtmlEditor.clean = [
40408 'script', 'style', 'title', 'xml'
40410 Roo.form.HtmlEditor.remove = [
40415 Roo.form.HtmlEditor.ablack = [
40419 Roo.form.HtmlEditor.aclean = [
40420 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
40424 Roo.form.HtmlEditor.pwhite= [
40425 'http', 'https', 'mailto'
40428 // white listed style attributes.
40429 Roo.form.HtmlEditor.cwhite= [
40435 Roo.form.HtmlEditor.swapCodes =[
40446 // <script type="text/javascript">
40449 * Ext JS Library 1.1.1
40450 * Copyright(c) 2006-2007, Ext JS, LLC.
40456 * @class Roo.form.HtmlEditorToolbar1
40461 new Roo.form.HtmlEditor({
40464 new Roo.form.HtmlEditorToolbar1({
40465 disable : { fonts: 1 , format: 1, ..., ... , ...],
40471 * @cfg {Object} disable List of elements to disable..
40472 * @cfg {Array} btns List of additional buttons.
40476 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
40479 Roo.form.HtmlEditor.ToolbarStandard = function(config)
40482 Roo.apply(this, config);
40484 // default disabled, based on 'good practice'..
40485 this.disable = this.disable || {};
40486 Roo.applyIf(this.disable, {
40489 specialElements : true
40493 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40494 // dont call parent... till later.
40497 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
40505 * @cfg {Object} disable List of toolbar elements to disable
40510 * @cfg {Array} fontFamilies An array of available font families
40528 // "á" , ?? a acute?
40533 "°" // , // degrees
40535 // "é" , // e ecute
40536 // "ú" , // u ecute?
40539 specialElements : [
40541 text: "Insert Table",
40544 ihtml : '<table><tr><td>Cell</td></tr></table>'
40548 text: "Insert Image",
40551 ihtml : '<img src="about:blank"/>'
40560 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
40561 "input:submit", "input:button", "select", "textarea", "label" ],
40564 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
40566 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
40569 * @cfg {String} defaultFont default font to use.
40571 defaultFont: 'tahoma',
40573 fontSelect : false,
40576 formatCombo : false,
40578 init : function(editor)
40580 this.editor = editor;
40583 var fid = editor.frameId;
40585 function btn(id, toggle, handler){
40586 var xid = fid + '-'+ id ;
40590 cls : 'x-btn-icon x-edit-'+id,
40591 enableToggle:toggle !== false,
40592 scope: editor, // was editor...
40593 handler:handler||editor.relayBtnCmd,
40594 clickEvent:'mousedown',
40595 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40602 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
40604 // stop form submits
40605 tb.el.on('click', function(e){
40606 e.preventDefault(); // what does this do?
40609 if(!this.disable.font && !Roo.isSafari){
40610 /* why no safari for fonts
40611 editor.fontSelect = tb.el.createChild({
40614 cls:'x-font-select',
40615 html: editor.createFontOptions()
40617 editor.fontSelect.on('change', function(){
40618 var font = editor.fontSelect.dom.value;
40619 editor.relayCmd('fontname', font);
40620 editor.deferFocus();
40623 editor.fontSelect.dom,
40628 if(!this.disable.formats){
40629 this.formatCombo = new Roo.form.ComboBox({
40630 store: new Roo.data.SimpleStore({
40633 data : this.formats // from states.js
40636 //autoCreate : {tag: "div", size: "20"},
40637 displayField:'tag',
40641 triggerAction: 'all',
40642 emptyText:'Add tag',
40643 selectOnFocus:true,
40646 'select': function(c, r, i) {
40647 editor.insertTag(r.get('tag'));
40653 tb.addField(this.formatCombo);
40657 if(!this.disable.format){
40664 if(!this.disable.fontSize){
40669 btn('increasefontsize', false, editor.adjustFont),
40670 btn('decreasefontsize', false, editor.adjustFont)
40675 if(!this.disable.colors){
40678 id:editor.frameId +'-forecolor',
40679 cls:'x-btn-icon x-edit-forecolor',
40680 clickEvent:'mousedown',
40681 tooltip: this.buttonTips['forecolor'] || undefined,
40683 menu : new Roo.menu.ColorMenu({
40684 allowReselect: true,
40685 focus: Roo.emptyFn,
40688 selectHandler: function(cp, color){
40689 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
40690 editor.deferFocus();
40693 clickEvent:'mousedown'
40696 id:editor.frameId +'backcolor',
40697 cls:'x-btn-icon x-edit-backcolor',
40698 clickEvent:'mousedown',
40699 tooltip: this.buttonTips['backcolor'] || undefined,
40701 menu : new Roo.menu.ColorMenu({
40702 focus: Roo.emptyFn,
40705 allowReselect: true,
40706 selectHandler: function(cp, color){
40708 editor.execCmd('useCSS', false);
40709 editor.execCmd('hilitecolor', color);
40710 editor.execCmd('useCSS', true);
40711 editor.deferFocus();
40713 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
40714 Roo.isSafari || Roo.isIE ? '#'+color : color);
40715 editor.deferFocus();
40719 clickEvent:'mousedown'
40724 // now add all the items...
40727 if(!this.disable.alignments){
40730 btn('justifyleft'),
40731 btn('justifycenter'),
40732 btn('justifyright')
40736 //if(!Roo.isSafari){
40737 if(!this.disable.links){
40740 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
40744 if(!this.disable.lists){
40747 btn('insertorderedlist'),
40748 btn('insertunorderedlist')
40751 if(!this.disable.sourceEdit){
40754 btn('sourceedit', true, function(btn){
40755 this.toggleSourceEdit(btn.pressed);
40762 // special menu.. - needs to be tidied up..
40763 if (!this.disable.special) {
40766 cls: 'x-edit-none',
40772 for (var i =0; i < this.specialChars.length; i++) {
40773 smenu.menu.items.push({
40775 html: this.specialChars[i],
40776 handler: function(a,b) {
40777 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
40778 //editor.insertAtCursor(a.html);
40791 if (!this.disable.specialElements) {
40794 cls: 'x-edit-none',
40799 for (var i =0; i < this.specialElements.length; i++) {
40800 semenu.menu.items.push(
40802 handler: function(a,b) {
40803 editor.insertAtCursor(this.ihtml);
40805 }, this.specialElements[i])
40817 for(var i =0; i< this.btns.length;i++) {
40818 var b = Roo.factory(this.btns[i],Roo.form);
40819 b.cls = 'x-edit-none';
40828 // disable everything...
40830 this.tb.items.each(function(item){
40831 if(item.id != editor.frameId+ '-sourceedit'){
40835 this.rendered = true;
40837 // the all the btns;
40838 editor.on('editorevent', this.updateToolbar, this);
40839 // other toolbars need to implement this..
40840 //editor.on('editmodechange', this.updateToolbar, this);
40846 * Protected method that will not generally be called directly. It triggers
40847 * a toolbar update by reading the markup state of the current selection in the editor.
40849 updateToolbar: function(){
40851 if(!this.editor.activated){
40852 this.editor.onFirstFocus();
40856 var btns = this.tb.items.map,
40857 doc = this.editor.doc,
40858 frameId = this.editor.frameId;
40860 if(!this.disable.font && !Roo.isSafari){
40862 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
40863 if(name != this.fontSelect.dom.value){
40864 this.fontSelect.dom.value = name;
40868 if(!this.disable.format){
40869 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
40870 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
40871 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
40873 if(!this.disable.alignments){
40874 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
40875 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
40876 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
40878 if(!Roo.isSafari && !this.disable.lists){
40879 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
40880 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
40883 var ans = this.editor.getAllAncestors();
40884 if (this.formatCombo) {
40887 var store = this.formatCombo.store;
40888 this.formatCombo.setValue("");
40889 for (var i =0; i < ans.length;i++) {
40890 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
40892 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
40900 // hides menus... - so this cant be on a menu...
40901 Roo.menu.MenuMgr.hideAll();
40903 //this.editorsyncValue();
40907 createFontOptions : function(){
40908 var buf = [], fs = this.fontFamilies, ff, lc;
40909 for(var i = 0, len = fs.length; i< len; i++){
40911 lc = ff.toLowerCase();
40913 '<option value="',lc,'" style="font-family:',ff,';"',
40914 (this.defaultFont == lc ? ' selected="true">' : '>'),
40919 return buf.join('');
40922 toggleSourceEdit : function(sourceEditMode){
40923 if(sourceEditMode === undefined){
40924 sourceEditMode = !this.sourceEditMode;
40926 this.sourceEditMode = sourceEditMode === true;
40927 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
40928 // just toggle the button?
40929 if(btn.pressed !== this.editor.sourceEditMode){
40930 btn.toggle(this.editor.sourceEditMode);
40934 if(this.sourceEditMode){
40935 this.tb.items.each(function(item){
40936 if(item.cmd != 'sourceedit'){
40942 if(this.initialized){
40943 this.tb.items.each(function(item){
40949 // tell the editor that it's been pressed..
40950 this.editor.toggleSourceEdit(sourceEditMode);
40954 * Object collection of toolbar tooltips for the buttons in the editor. The key
40955 * is the command id associated with that button and the value is a valid QuickTips object.
40960 title: 'Bold (Ctrl+B)',
40961 text: 'Make the selected text bold.',
40962 cls: 'x-html-editor-tip'
40965 title: 'Italic (Ctrl+I)',
40966 text: 'Make the selected text italic.',
40967 cls: 'x-html-editor-tip'
40975 title: 'Bold (Ctrl+B)',
40976 text: 'Make the selected text bold.',
40977 cls: 'x-html-editor-tip'
40980 title: 'Italic (Ctrl+I)',
40981 text: 'Make the selected text italic.',
40982 cls: 'x-html-editor-tip'
40985 title: 'Underline (Ctrl+U)',
40986 text: 'Underline the selected text.',
40987 cls: 'x-html-editor-tip'
40989 increasefontsize : {
40990 title: 'Grow Text',
40991 text: 'Increase the font size.',
40992 cls: 'x-html-editor-tip'
40994 decreasefontsize : {
40995 title: 'Shrink Text',
40996 text: 'Decrease the font size.',
40997 cls: 'x-html-editor-tip'
41000 title: 'Text Highlight Color',
41001 text: 'Change the background color of the selected text.',
41002 cls: 'x-html-editor-tip'
41005 title: 'Font Color',
41006 text: 'Change the color of the selected text.',
41007 cls: 'x-html-editor-tip'
41010 title: 'Align Text Left',
41011 text: 'Align text to the left.',
41012 cls: 'x-html-editor-tip'
41015 title: 'Center Text',
41016 text: 'Center text in the editor.',
41017 cls: 'x-html-editor-tip'
41020 title: 'Align Text Right',
41021 text: 'Align text to the right.',
41022 cls: 'x-html-editor-tip'
41024 insertunorderedlist : {
41025 title: 'Bullet List',
41026 text: 'Start a bulleted list.',
41027 cls: 'x-html-editor-tip'
41029 insertorderedlist : {
41030 title: 'Numbered List',
41031 text: 'Start a numbered list.',
41032 cls: 'x-html-editor-tip'
41035 title: 'Hyperlink',
41036 text: 'Make the selected text a hyperlink.',
41037 cls: 'x-html-editor-tip'
41040 title: 'Source Edit',
41041 text: 'Switch to source editing mode.',
41042 cls: 'x-html-editor-tip'
41046 onDestroy : function(){
41049 this.tb.items.each(function(item){
41051 item.menu.removeAll();
41053 item.menu.el.destroy();
41061 onFirstFocus: function() {
41062 this.tb.items.each(function(item){
41071 // <script type="text/javascript">
41074 * Ext JS Library 1.1.1
41075 * Copyright(c) 2006-2007, Ext JS, LLC.
41082 * @class Roo.form.HtmlEditor.ToolbarContext
41087 new Roo.form.HtmlEditor({
41090 { xtype: 'ToolbarStandard', styles : {} }
41091 { xtype: 'ToolbarContext', disable : {} }
41097 * @config : {Object} disable List of elements to disable.. (not done yet.)
41098 * @config : {Object} styles Map of styles available.
41102 Roo.form.HtmlEditor.ToolbarContext = function(config)
41105 Roo.apply(this, config);
41106 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41107 // dont call parent... till later.
41108 this.styles = this.styles || {};
41110 Roo.form.HtmlEditor.ToolbarContext.types = {
41122 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
41184 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
41189 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
41243 // should we really allow this??
41244 // should this just be
41259 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
41267 * @cfg {Object} disable List of toolbar elements to disable
41272 * @cfg {Object} styles List of styles
41273 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
41275 * These must be defined in the page, so they get rendered correctly..
41286 init : function(editor)
41288 this.editor = editor;
41291 var fid = editor.frameId;
41293 function btn(id, toggle, handler){
41294 var xid = fid + '-'+ id ;
41298 cls : 'x-btn-icon x-edit-'+id,
41299 enableToggle:toggle !== false,
41300 scope: editor, // was editor...
41301 handler:handler||editor.relayBtnCmd,
41302 clickEvent:'mousedown',
41303 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41307 // create a new element.
41308 var wdiv = editor.wrap.createChild({
41310 }, editor.wrap.dom.firstChild.nextSibling, true);
41312 // can we do this more than once??
41314 // stop form submits
41317 // disable everything...
41318 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
41319 this.toolbars = {};
41321 for (var i in ty) {
41323 this.toolbars[i] = this.buildToolbar(ty[i],i);
41325 this.tb = this.toolbars.BODY;
41327 this.buildFooter();
41328 this.footer.show();
41329 editor.on('hide', function( ) { this.footer.hide() }, this);
41330 editor.on('show', function( ) { this.footer.show() }, this);
41333 this.rendered = true;
41335 // the all the btns;
41336 editor.on('editorevent', this.updateToolbar, this);
41337 // other toolbars need to implement this..
41338 //editor.on('editmodechange', this.updateToolbar, this);
41344 * Protected method that will not generally be called directly. It triggers
41345 * a toolbar update by reading the markup state of the current selection in the editor.
41347 updateToolbar: function(editor,ev,sel){
41350 // capture mouse up - this is handy for selecting images..
41351 // perhaps should go somewhere else...
41352 if(!this.editor.activated){
41353 this.editor.onFirstFocus();
41357 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
41358 // selectNode - might want to handle IE?
41360 (ev.type == 'mouseup' || ev.type == 'click' ) &&
41361 ev.target && ev.target.tagName == 'IMG') {
41362 // they have click on an image...
41363 // let's see if we can change the selection...
41366 var nodeRange = sel.ownerDocument.createRange();
41368 nodeRange.selectNode(sel);
41370 nodeRange.selectNodeContents(sel);
41372 //nodeRange.collapse(true);
41373 var s = editor.win.getSelection();
41374 s.removeAllRanges();
41375 s.addRange(nodeRange);
41379 var updateFooter = sel ? false : true;
41382 var ans = this.editor.getAllAncestors();
41385 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
41388 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
41389 sel = sel ? sel : this.editor.doc.body;
41390 sel = sel.tagName.length ? sel : this.editor.doc.body;
41393 // pick a menu that exists..
41394 var tn = sel.tagName.toUpperCase();
41395 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
41397 tn = sel.tagName.toUpperCase();
41399 var lastSel = this.tb.selectedNode
41401 this.tb.selectedNode = sel;
41403 // if current menu does not match..
41404 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
41407 ///console.log("show: " + tn);
41408 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
41411 this.tb.items.first().el.innerHTML = tn + ': ';
41414 // update attributes
41415 if (this.tb.fields) {
41416 this.tb.fields.each(function(e) {
41417 e.setValue(sel.getAttribute(e.attrname));
41421 var hasStyles = false;
41422 for(var i in this.styles) {
41429 var st = this.tb.fields.item(0);
41431 st.store.removeAll();
41434 var cn = sel.className.split(/\s+/);
41437 if (this.styles['*']) {
41439 Roo.each(this.styles['*'], function(v) {
41440 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
41443 if (this.styles[tn]) {
41444 Roo.each(this.styles[tn], function(v) {
41445 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
41449 st.store.loadData(avs);
41453 // flag our selected Node.
41454 this.tb.selectedNode = sel;
41457 Roo.menu.MenuMgr.hideAll();
41461 if (!updateFooter) {
41464 // update the footer
41468 this.footerEls = ans.reverse();
41469 Roo.each(this.footerEls, function(a,i) {
41470 if (!a) { return; }
41471 html += html.length ? ' > ' : '';
41473 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
41478 var sz = this.footDisp.up('td').getSize();
41479 this.footDisp.dom.style.width = (sz.width -10) + 'px';
41480 this.footDisp.dom.style.marginLeft = '5px';
41482 this.footDisp.dom.style.overflow = 'hidden';
41484 this.footDisp.dom.innerHTML = html;
41486 //this.editorsyncValue();
41491 onDestroy : function(){
41494 this.tb.items.each(function(item){
41496 item.menu.removeAll();
41498 item.menu.el.destroy();
41506 onFirstFocus: function() {
41507 // need to do this for all the toolbars..
41508 this.tb.items.each(function(item){
41512 buildToolbar: function(tlist, nm)
41514 var editor = this.editor;
41515 // create a new element.
41516 var wdiv = editor.wrap.createChild({
41518 }, editor.wrap.dom.firstChild.nextSibling, true);
41521 var tb = new Roo.Toolbar(wdiv);
41524 tb.add(nm+ ": ");
41527 for(var i in this.styles) {
41532 if (styles && styles.length) {
41534 // this needs a multi-select checkbox...
41535 tb.addField( new Roo.form.ComboBox({
41536 store: new Roo.data.SimpleStore({
41538 fields: ['val', 'selected'],
41541 name : '-roo-edit-className',
41542 attrname : 'className',
41543 displayField:'val',
41547 triggerAction: 'all',
41548 emptyText:'Select Style',
41549 selectOnFocus:true,
41552 'select': function(c, r, i) {
41553 // initial support only for on class per el..
41554 tb.selectedNode.className = r ? r.get('val') : '';
41555 editor.syncValue();
41564 for (var i in tlist) {
41566 var item = tlist[i];
41567 tb.add(item.title + ": ");
41573 // opts == pulldown..
41574 tb.addField( new Roo.form.ComboBox({
41575 store: new Roo.data.SimpleStore({
41580 name : '-roo-edit-' + i,
41582 displayField:'val',
41586 triggerAction: 'all',
41587 emptyText:'Select',
41588 selectOnFocus:true,
41589 width: item.width ? item.width : 130,
41591 'select': function(c, r, i) {
41592 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
41601 tb.addField( new Roo.form.TextField({
41604 //allowBlank:false,
41609 tb.addField( new Roo.form.TextField({
41610 name: '-roo-edit-' + i,
41617 'change' : function(f, nv, ov) {
41618 tb.selectedNode.setAttribute(f.attrname, nv);
41624 tb.el.on('click', function(e){
41625 e.preventDefault(); // what does this do?
41627 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
41630 // dont need to disable them... as they will get hidden
41635 buildFooter : function()
41638 var fel = this.editor.wrap.createChild();
41639 this.footer = new Roo.Toolbar(fel);
41640 // toolbar has scrolly on left / right?
41641 var footDisp= new Roo.Toolbar.Fill();
41647 handler : function() {
41648 _t.footDisp.scrollTo('left',0,true)
41652 this.footer.add( footDisp );
41657 handler : function() {
41659 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
41663 var fel = Roo.get(footDisp.el);
41664 fel.addClass('x-editor-context');
41665 this.footDispWrap = fel;
41666 this.footDispWrap.overflow = 'hidden';
41668 this.footDisp = fel.createChild();
41669 this.footDispWrap.on('click', this.onContextClick, this)
41673 onContextClick : function (ev,dom)
41675 ev.preventDefault();
41676 var cn = dom.className;
41678 if (!cn.match(/x-ed-loc-/)) {
41681 var n = cn.split('-').pop();
41682 var ans = this.footerEls;
41686 var range = this.editor.createRange();
41688 range.selectNodeContents(sel);
41689 //range.selectNode(sel);
41692 var selection = this.editor.getSelection();
41693 selection.removeAllRanges();
41694 selection.addRange(range);
41698 this.updateToolbar(null, null, sel);
41715 * Ext JS Library 1.1.1
41716 * Copyright(c) 2006-2007, Ext JS, LLC.
41718 * Originally Released Under LGPL - original licence link has changed is not relivant.
41721 * <script type="text/javascript">
41725 * @class Roo.form.BasicForm
41726 * @extends Roo.util.Observable
41727 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
41729 * @param {String/HTMLElement/Roo.Element} el The form element or its id
41730 * @param {Object} config Configuration options
41732 Roo.form.BasicForm = function(el, config){
41733 this.allItems = [];
41734 this.childForms = [];
41735 Roo.apply(this, config);
41737 * The Roo.form.Field items in this form.
41738 * @type MixedCollection
41742 this.items = new Roo.util.MixedCollection(false, function(o){
41743 return o.id || (o.id = Roo.id());
41747 * @event beforeaction
41748 * Fires before any action is performed. Return false to cancel the action.
41749 * @param {Form} this
41750 * @param {Action} action The action to be performed
41752 beforeaction: true,
41754 * @event actionfailed
41755 * Fires when an action fails.
41756 * @param {Form} this
41757 * @param {Action} action The action that failed
41759 actionfailed : true,
41761 * @event actioncomplete
41762 * Fires when an action is completed.
41763 * @param {Form} this
41764 * @param {Action} action The action that completed
41766 actioncomplete : true
41771 Roo.form.BasicForm.superclass.constructor.call(this);
41774 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
41776 * @cfg {String} method
41777 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
41780 * @cfg {DataReader} reader
41781 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
41782 * This is optional as there is built-in support for processing JSON.
41785 * @cfg {DataReader} errorReader
41786 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
41787 * This is completely optional as there is built-in support for processing JSON.
41790 * @cfg {String} url
41791 * The URL to use for form actions if one isn't supplied in the action options.
41794 * @cfg {Boolean} fileUpload
41795 * Set to true if this form is a file upload.
41799 * @cfg {Object} baseParams
41800 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
41805 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
41810 activeAction : null,
41813 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
41814 * or setValues() data instead of when the form was first created.
41816 trackResetOnLoad : false,
41820 * childForms - used for multi-tab forms
41823 childForms : false,
41826 * allItems - full list of fields.
41832 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
41833 * element by passing it or its id or mask the form itself by passing in true.
41836 waitMsgTarget : false,
41839 initEl : function(el){
41840 this.el = Roo.get(el);
41841 this.id = this.el.id || Roo.id();
41842 this.el.on('submit', this.onSubmit, this);
41843 this.el.addClass('x-form');
41847 onSubmit : function(e){
41852 * Returns true if client-side validation on the form is successful.
41855 isValid : function(){
41857 this.items.each(function(f){
41866 * Returns true if any fields in this form have changed since their original load.
41869 isDirty : function(){
41871 this.items.each(function(f){
41881 * Performs a predefined action (submit or load) or custom actions you define on this form.
41882 * @param {String} actionName The name of the action type
41883 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
41884 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
41885 * accept other config options):
41887 Property Type Description
41888 ---------------- --------------- ----------------------------------------------------------------------------------
41889 url String The url for the action (defaults to the form's url)
41890 method String The form method to use (defaults to the form's method, or POST if not defined)
41891 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
41892 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
41893 validate the form on the client (defaults to false)
41895 * @return {BasicForm} this
41897 doAction : function(action, options){
41898 if(typeof action == 'string'){
41899 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
41901 if(this.fireEvent('beforeaction', this, action) !== false){
41902 this.beforeAction(action);
41903 action.run.defer(100, action);
41909 * Shortcut to do a submit action.
41910 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41911 * @return {BasicForm} this
41913 submit : function(options){
41914 this.doAction('submit', options);
41919 * Shortcut to do a load action.
41920 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41921 * @return {BasicForm} this
41923 load : function(options){
41924 this.doAction('load', options);
41929 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
41930 * @param {Record} record The record to edit
41931 * @return {BasicForm} this
41933 updateRecord : function(record){
41934 record.beginEdit();
41935 var fs = record.fields;
41936 fs.each(function(f){
41937 var field = this.findField(f.name);
41939 record.set(f.name, field.getValue());
41947 * Loads an Roo.data.Record into this form.
41948 * @param {Record} record The record to load
41949 * @return {BasicForm} this
41951 loadRecord : function(record){
41952 this.setValues(record.data);
41957 beforeAction : function(action){
41958 var o = action.options;
41961 if(this.waitMsgTarget === true){
41962 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
41963 }else if(this.waitMsgTarget){
41964 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
41965 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
41967 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
41973 afterAction : function(action, success){
41974 this.activeAction = null;
41975 var o = action.options;
41977 if(this.waitMsgTarget === true){
41979 }else if(this.waitMsgTarget){
41980 this.waitMsgTarget.unmask();
41982 Roo.MessageBox.updateProgress(1);
41983 Roo.MessageBox.hide();
41990 Roo.callback(o.success, o.scope, [this, action]);
41991 this.fireEvent('actioncomplete', this, action);
41995 // failure condition..
41996 // we have a scenario where updates need confirming.
41997 // eg. if a locking scenario exists..
41998 // we look for { errors : { needs_confirm : true }} in the response.
42000 (typeof(action.result) != 'undefined') &&
42001 (typeof(action.result.errors) != 'undefined') &&
42002 (typeof(action.result.errors.needs_confirm) != 'undefined')
42005 Roo.MessageBox.confirm(
42006 "Change requires confirmation",
42007 action.result.errorMsg,
42012 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
42022 Roo.callback(o.failure, o.scope, [this, action]);
42023 // show an error message if no failed handler is set..
42024 if (!this.hasListener('actionfailed')) {
42025 Roo.MessageBox.alert("Error",
42026 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
42027 action.result.errorMsg :
42028 "Saving Failed, please check your entries or try again"
42032 this.fireEvent('actionfailed', this, action);
42038 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
42039 * @param {String} id The value to search for
42042 findField : function(id){
42043 var field = this.items.get(id);
42045 this.items.each(function(f){
42046 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
42052 return field || null;
42056 * Add a secondary form to this one,
42057 * Used to provide tabbed forms. One form is primary, with hidden values
42058 * which mirror the elements from the other forms.
42060 * @param {Roo.form.Form} form to add.
42063 addForm : function(form)
42066 if (this.childForms.indexOf(form) > -1) {
42070 this.childForms.push(form);
42072 Roo.each(form.allItems, function (fe) {
42074 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
42075 if (this.findField(n)) { // already added..
42078 var add = new Roo.form.Hidden({
42081 add.render(this.el);
42088 * Mark fields in this form invalid in bulk.
42089 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
42090 * @return {BasicForm} this
42092 markInvalid : function(errors){
42093 if(errors instanceof Array){
42094 for(var i = 0, len = errors.length; i < len; i++){
42095 var fieldError = errors[i];
42096 var f = this.findField(fieldError.id);
42098 f.markInvalid(fieldError.msg);
42104 if(typeof errors[id] != 'function' && (field = this.findField(id))){
42105 field.markInvalid(errors[id]);
42109 Roo.each(this.childForms || [], function (f) {
42110 f.markInvalid(errors);
42117 * Set values for fields in this form in bulk.
42118 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
42119 * @return {BasicForm} this
42121 setValues : function(values){
42122 if(values instanceof Array){ // array of objects
42123 for(var i = 0, len = values.length; i < len; i++){
42125 var f = this.findField(v.id);
42127 f.setValue(v.value);
42128 if(this.trackResetOnLoad){
42129 f.originalValue = f.getValue();
42133 }else{ // object hash
42136 if(typeof values[id] != 'function' && (field = this.findField(id))){
42138 if (field.setFromData &&
42139 field.valueField &&
42140 field.displayField &&
42141 // combos' with local stores can
42142 // be queried via setValue()
42143 // to set their value..
42144 (field.store && !field.store.isLocal)
42148 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
42149 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
42150 field.setFromData(sd);
42153 field.setValue(values[id]);
42157 if(this.trackResetOnLoad){
42158 field.originalValue = field.getValue();
42164 Roo.each(this.childForms || [], function (f) {
42165 f.setValues(values);
42172 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
42173 * they are returned as an array.
42174 * @param {Boolean} asString
42177 getValues : function(asString){
42178 if (this.childForms) {
42179 // copy values from the child forms
42180 Roo.each(this.childForms, function (f) {
42181 this.setValues(f.getValues());
42187 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
42188 if(asString === true){
42191 return Roo.urlDecode(fs);
42195 * Returns the fields in this form as an object with key/value pairs.
42196 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
42199 getFieldValues : function(with_hidden)
42201 if (this.childForms) {
42202 // copy values from the child forms
42203 // should this call getFieldValues - probably not as we do not currently copy
42204 // hidden fields when we generate..
42205 Roo.each(this.childForms, function (f) {
42206 this.setValues(f.getValues());
42211 this.items.each(function(f){
42212 if (!f.getName()) {
42215 var v = f.getValue();
42216 // not sure if this supported any more..
42217 if ((typeof(v) == 'object') && f.getRawValue) {
42218 v = f.getRawValue() ; // dates..
42220 // combo boxes where name != hiddenName...
42221 if (f.name != f.getName()) {
42222 ret[f.name] = f.getRawValue();
42224 ret[f.getName()] = v;
42231 * Clears all invalid messages in this form.
42232 * @return {BasicForm} this
42234 clearInvalid : function(){
42235 this.items.each(function(f){
42239 Roo.each(this.childForms || [], function (f) {
42248 * Resets this form.
42249 * @return {BasicForm} this
42251 reset : function(){
42252 this.items.each(function(f){
42256 Roo.each(this.childForms || [], function (f) {
42265 * Add Roo.form components to this form.
42266 * @param {Field} field1
42267 * @param {Field} field2 (optional)
42268 * @param {Field} etc (optional)
42269 * @return {BasicForm} this
42272 this.items.addAll(Array.prototype.slice.call(arguments, 0));
42278 * Removes a field from the items collection (does NOT remove its markup).
42279 * @param {Field} field
42280 * @return {BasicForm} this
42282 remove : function(field){
42283 this.items.remove(field);
42288 * Looks at the fields in this form, checks them for an id attribute,
42289 * and calls applyTo on the existing dom element with that id.
42290 * @return {BasicForm} this
42292 render : function(){
42293 this.items.each(function(f){
42294 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
42302 * Calls {@link Ext#apply} for all fields in this form with the passed object.
42303 * @param {Object} values
42304 * @return {BasicForm} this
42306 applyToFields : function(o){
42307 this.items.each(function(f){
42314 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
42315 * @param {Object} values
42316 * @return {BasicForm} this
42318 applyIfToFields : function(o){
42319 this.items.each(function(f){
42327 Roo.BasicForm = Roo.form.BasicForm;/*
42329 * Ext JS Library 1.1.1
42330 * Copyright(c) 2006-2007, Ext JS, LLC.
42332 * Originally Released Under LGPL - original licence link has changed is not relivant.
42335 * <script type="text/javascript">
42339 * @class Roo.form.Form
42340 * @extends Roo.form.BasicForm
42341 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
42343 * @param {Object} config Configuration options
42345 Roo.form.Form = function(config){
42347 if (config.items) {
42348 xitems = config.items;
42349 delete config.items;
42353 Roo.form.Form.superclass.constructor.call(this, null, config);
42354 this.url = this.url || this.action;
42356 this.root = new Roo.form.Layout(Roo.applyIf({
42360 this.active = this.root;
42362 * Array of all the buttons that have been added to this form via {@link addButton}
42366 this.allItems = [];
42369 * @event clientvalidation
42370 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
42371 * @param {Form} this
42372 * @param {Boolean} valid true if the form has passed client-side validation
42374 clientvalidation: true,
42377 * Fires when the form is rendered
42378 * @param {Roo.form.Form} form
42383 if (this.progressUrl) {
42384 // push a hidden field onto the list of fields..
42388 name : 'UPLOAD_IDENTIFIER'
42393 Roo.each(xitems, this.addxtype, this);
42399 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
42401 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
42404 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
42407 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
42409 buttonAlign:'center',
42412 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
42417 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
42418 * This property cascades to child containers if not set.
42423 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
42424 * fires a looping event with that state. This is required to bind buttons to the valid
42425 * state using the config value formBind:true on the button.
42427 monitorValid : false,
42430 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
42435 * @cfg {String} progressUrl - Url to return progress data
42438 progressUrl : false,
42441 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
42442 * fields are added and the column is closed. If no fields are passed the column remains open
42443 * until end() is called.
42444 * @param {Object} config The config to pass to the column
42445 * @param {Field} field1 (optional)
42446 * @param {Field} field2 (optional)
42447 * @param {Field} etc (optional)
42448 * @return Column The column container object
42450 column : function(c){
42451 var col = new Roo.form.Column(c);
42453 if(arguments.length > 1){ // duplicate code required because of Opera
42454 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42461 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
42462 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
42463 * until end() is called.
42464 * @param {Object} config The config to pass to the fieldset
42465 * @param {Field} field1 (optional)
42466 * @param {Field} field2 (optional)
42467 * @param {Field} etc (optional)
42468 * @return FieldSet The fieldset container object
42470 fieldset : function(c){
42471 var fs = new Roo.form.FieldSet(c);
42473 if(arguments.length > 1){ // duplicate code required because of Opera
42474 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42481 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
42482 * fields are added and the container is closed. If no fields are passed the container remains open
42483 * until end() is called.
42484 * @param {Object} config The config to pass to the Layout
42485 * @param {Field} field1 (optional)
42486 * @param {Field} field2 (optional)
42487 * @param {Field} etc (optional)
42488 * @return Layout The container object
42490 container : function(c){
42491 var l = new Roo.form.Layout(c);
42493 if(arguments.length > 1){ // duplicate code required because of Opera
42494 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42501 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
42502 * @param {Object} container A Roo.form.Layout or subclass of Layout
42503 * @return {Form} this
42505 start : function(c){
42506 // cascade label info
42507 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
42508 this.active.stack.push(c);
42509 c.ownerCt = this.active;
42515 * Closes the current open container
42516 * @return {Form} this
42519 if(this.active == this.root){
42522 this.active = this.active.ownerCt;
42527 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
42528 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
42529 * as the label of the field.
42530 * @param {Field} field1
42531 * @param {Field} field2 (optional)
42532 * @param {Field} etc. (optional)
42533 * @return {Form} this
42536 this.active.stack.push.apply(this.active.stack, arguments);
42537 this.allItems.push.apply(this.allItems,arguments);
42539 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
42540 if(a[i].isFormField){
42545 Roo.form.Form.superclass.add.apply(this, r);
42555 * Find any element that has been added to a form, using it's ID or name
42556 * This can include framesets, columns etc. along with regular fields..
42557 * @param {String} id - id or name to find.
42559 * @return {Element} e - or false if nothing found.
42561 findbyId : function(id)
42567 Roo.each(this.allItems, function(f){
42568 if (f.id == id || f.name == id ){
42579 * Render this form into the passed container. This should only be called once!
42580 * @param {String/HTMLElement/Element} container The element this component should be rendered into
42581 * @return {Form} this
42583 render : function(ct)
42589 var o = this.autoCreate || {
42591 method : this.method || 'POST',
42592 id : this.id || Roo.id()
42594 this.initEl(ct.createChild(o));
42596 this.root.render(this.el);
42600 this.items.each(function(f){
42601 f.render('x-form-el-'+f.id);
42604 if(this.buttons.length > 0){
42605 // tables are required to maintain order and for correct IE layout
42606 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
42607 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
42608 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
42610 var tr = tb.getElementsByTagName('tr')[0];
42611 for(var i = 0, len = this.buttons.length; i < len; i++) {
42612 var b = this.buttons[i];
42613 var td = document.createElement('td');
42614 td.className = 'x-form-btn-td';
42615 b.render(tr.appendChild(td));
42618 if(this.monitorValid){ // initialize after render
42619 this.startMonitoring();
42621 this.fireEvent('rendered', this);
42626 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
42627 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
42628 * object or a valid Roo.DomHelper element config
42629 * @param {Function} handler The function called when the button is clicked
42630 * @param {Object} scope (optional) The scope of the handler function
42631 * @return {Roo.Button}
42633 addButton : function(config, handler, scope){
42637 minWidth: this.minButtonWidth,
42640 if(typeof config == "string"){
42643 Roo.apply(bc, config);
42645 var btn = new Roo.Button(null, bc);
42646 this.buttons.push(btn);
42651 * Adds a series of form elements (using the xtype property as the factory method.
42652 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
42653 * @param {Object} config
42656 addxtype : function()
42658 var ar = Array.prototype.slice.call(arguments, 0);
42660 for(var i = 0; i < ar.length; i++) {
42662 continue; // skip -- if this happends something invalid got sent, we
42663 // should ignore it, as basically that interface element will not show up
42664 // and that should be pretty obvious!!
42667 if (Roo.form[ar[i].xtype]) {
42669 var fe = Roo.factory(ar[i], Roo.form);
42675 fe.store.form = this;
42680 this.allItems.push(fe);
42681 if (fe.items && fe.addxtype) {
42682 fe.addxtype.apply(fe, fe.items);
42692 // console.log('adding ' + ar[i].xtype);
42694 if (ar[i].xtype == 'Button') {
42695 //console.log('adding button');
42696 //console.log(ar[i]);
42697 this.addButton(ar[i]);
42698 this.allItems.push(fe);
42702 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
42703 alert('end is not supported on xtype any more, use items');
42705 // //console.log('adding end');
42713 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
42714 * option "monitorValid"
42716 startMonitoring : function(){
42719 Roo.TaskMgr.start({
42720 run : this.bindHandler,
42721 interval : this.monitorPoll || 200,
42728 * Stops monitoring of the valid state of this form
42730 stopMonitoring : function(){
42731 this.bound = false;
42735 bindHandler : function(){
42737 return false; // stops binding
42740 this.items.each(function(f){
42741 if(!f.isValid(true)){
42746 for(var i = 0, len = this.buttons.length; i < len; i++){
42747 var btn = this.buttons[i];
42748 if(btn.formBind === true && btn.disabled === valid){
42749 btn.setDisabled(!valid);
42752 this.fireEvent('clientvalidation', this, valid);
42766 Roo.Form = Roo.form.Form;
42769 * Ext JS Library 1.1.1
42770 * Copyright(c) 2006-2007, Ext JS, LLC.
42772 * Originally Released Under LGPL - original licence link has changed is not relivant.
42775 * <script type="text/javascript">
42779 * @class Roo.form.Action
42780 * Internal Class used to handle form actions
42782 * @param {Roo.form.BasicForm} el The form element or its id
42783 * @param {Object} config Configuration options
42787 // define the action interface
42788 Roo.form.Action = function(form, options){
42790 this.options = options || {};
42793 * Client Validation Failed
42796 Roo.form.Action.CLIENT_INVALID = 'client';
42798 * Server Validation Failed
42801 Roo.form.Action.SERVER_INVALID = 'server';
42803 * Connect to Server Failed
42806 Roo.form.Action.CONNECT_FAILURE = 'connect';
42808 * Reading Data from Server Failed
42811 Roo.form.Action.LOAD_FAILURE = 'load';
42813 Roo.form.Action.prototype = {
42815 failureType : undefined,
42816 response : undefined,
42817 result : undefined,
42819 // interface method
42820 run : function(options){
42824 // interface method
42825 success : function(response){
42829 // interface method
42830 handleResponse : function(response){
42834 // default connection failure
42835 failure : function(response){
42837 this.response = response;
42838 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42839 this.form.afterAction(this, false);
42842 processResponse : function(response){
42843 this.response = response;
42844 if(!response.responseText){
42847 this.result = this.handleResponse(response);
42848 return this.result;
42851 // utility functions used internally
42852 getUrl : function(appendParams){
42853 var url = this.options.url || this.form.url || this.form.el.dom.action;
42855 var p = this.getParams();
42857 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
42863 getMethod : function(){
42864 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
42867 getParams : function(){
42868 var bp = this.form.baseParams;
42869 var p = this.options.params;
42871 if(typeof p == "object"){
42872 p = Roo.urlEncode(Roo.applyIf(p, bp));
42873 }else if(typeof p == 'string' && bp){
42874 p += '&' + Roo.urlEncode(bp);
42877 p = Roo.urlEncode(bp);
42882 createCallback : function(){
42884 success: this.success,
42885 failure: this.failure,
42887 timeout: (this.form.timeout*1000),
42888 upload: this.form.fileUpload ? this.success : undefined
42893 Roo.form.Action.Submit = function(form, options){
42894 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
42897 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
42900 haveProgress : false,
42901 uploadComplete : false,
42903 // uploadProgress indicator.
42904 uploadProgress : function()
42906 if (!this.form.progressUrl) {
42910 if (!this.haveProgress) {
42911 Roo.MessageBox.progress("Uploading", "Uploading");
42913 if (this.uploadComplete) {
42914 Roo.MessageBox.hide();
42918 this.haveProgress = true;
42920 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
42922 var c = new Roo.data.Connection();
42924 url : this.form.progressUrl,
42929 success : function(req){
42930 //console.log(data);
42934 rdata = Roo.decode(req.responseText)
42936 Roo.log("Invalid data from server..");
42940 if (!rdata || !rdata.success) {
42944 var data = rdata.data;
42946 if (this.uploadComplete) {
42947 Roo.MessageBox.hide();
42952 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
42953 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
42956 this.uploadProgress.defer(2000,this);
42959 failure: function(data) {
42960 Roo.log('progress url failed ');
42971 // run get Values on the form, so it syncs any secondary forms.
42972 this.form.getValues();
42974 var o = this.options;
42975 var method = this.getMethod();
42976 var isPost = method == 'POST';
42977 if(o.clientValidation === false || this.form.isValid()){
42979 if (this.form.progressUrl) {
42980 this.form.findField('UPLOAD_IDENTIFIER').setValue(
42981 (new Date() * 1) + '' + Math.random());
42986 Roo.Ajax.request(Roo.apply(this.createCallback(), {
42987 form:this.form.el.dom,
42988 url:this.getUrl(!isPost),
42990 params:isPost ? this.getParams() : null,
42991 isUpload: this.form.fileUpload
42994 this.uploadProgress();
42996 }else if (o.clientValidation !== false){ // client validation failed
42997 this.failureType = Roo.form.Action.CLIENT_INVALID;
42998 this.form.afterAction(this, false);
43002 success : function(response)
43004 this.uploadComplete= true;
43005 if (this.haveProgress) {
43006 Roo.MessageBox.hide();
43010 var result = this.processResponse(response);
43011 if(result === true || result.success){
43012 this.form.afterAction(this, true);
43016 this.form.markInvalid(result.errors);
43017 this.failureType = Roo.form.Action.SERVER_INVALID;
43019 this.form.afterAction(this, false);
43021 failure : function(response)
43023 this.uploadComplete= true;
43024 if (this.haveProgress) {
43025 Roo.MessageBox.hide();
43028 this.response = response;
43029 this.failureType = Roo.form.Action.CONNECT_FAILURE;
43030 this.form.afterAction(this, false);
43033 handleResponse : function(response){
43034 if(this.form.errorReader){
43035 var rs = this.form.errorReader.read(response);
43038 for(var i = 0, len = rs.records.length; i < len; i++) {
43039 var r = rs.records[i];
43040 errors[i] = r.data;
43043 if(errors.length < 1){
43047 success : rs.success,
43053 ret = Roo.decode(response.responseText);
43057 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
43067 Roo.form.Action.Load = function(form, options){
43068 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
43069 this.reader = this.form.reader;
43072 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
43077 Roo.Ajax.request(Roo.apply(
43078 this.createCallback(), {
43079 method:this.getMethod(),
43080 url:this.getUrl(false),
43081 params:this.getParams()
43085 success : function(response){
43087 var result = this.processResponse(response);
43088 if(result === true || !result.success || !result.data){
43089 this.failureType = Roo.form.Action.LOAD_FAILURE;
43090 this.form.afterAction(this, false);
43093 this.form.clearInvalid();
43094 this.form.setValues(result.data);
43095 this.form.afterAction(this, true);
43098 handleResponse : function(response){
43099 if(this.form.reader){
43100 var rs = this.form.reader.read(response);
43101 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
43103 success : rs.success,
43107 return Roo.decode(response.responseText);
43111 Roo.form.Action.ACTION_TYPES = {
43112 'load' : Roo.form.Action.Load,
43113 'submit' : Roo.form.Action.Submit
43116 * Ext JS Library 1.1.1
43117 * Copyright(c) 2006-2007, Ext JS, LLC.
43119 * Originally Released Under LGPL - original licence link has changed is not relivant.
43122 * <script type="text/javascript">
43126 * @class Roo.form.Layout
43127 * @extends Roo.Component
43128 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
43130 * @param {Object} config Configuration options
43132 Roo.form.Layout = function(config){
43134 if (config.items) {
43135 xitems = config.items;
43136 delete config.items;
43138 Roo.form.Layout.superclass.constructor.call(this, config);
43140 Roo.each(xitems, this.addxtype, this);
43144 Roo.extend(Roo.form.Layout, Roo.Component, {
43146 * @cfg {String/Object} autoCreate
43147 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
43150 * @cfg {String/Object/Function} style
43151 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
43152 * a function which returns such a specification.
43155 * @cfg {String} labelAlign
43156 * Valid values are "left," "top" and "right" (defaults to "left")
43159 * @cfg {Number} labelWidth
43160 * Fixed width in pixels of all field labels (defaults to undefined)
43163 * @cfg {Boolean} clear
43164 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
43168 * @cfg {String} labelSeparator
43169 * The separator to use after field labels (defaults to ':')
43171 labelSeparator : ':',
43173 * @cfg {Boolean} hideLabels
43174 * True to suppress the display of field labels in this layout (defaults to false)
43176 hideLabels : false,
43179 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
43184 onRender : function(ct, position){
43185 if(this.el){ // from markup
43186 this.el = Roo.get(this.el);
43187 }else { // generate
43188 var cfg = this.getAutoCreate();
43189 this.el = ct.createChild(cfg, position);
43192 this.el.applyStyles(this.style);
43194 if(this.labelAlign){
43195 this.el.addClass('x-form-label-'+this.labelAlign);
43197 if(this.hideLabels){
43198 this.labelStyle = "display:none";
43199 this.elementStyle = "padding-left:0;";
43201 if(typeof this.labelWidth == 'number'){
43202 this.labelStyle = "width:"+this.labelWidth+"px;";
43203 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
43205 if(this.labelAlign == 'top'){
43206 this.labelStyle = "width:auto;";
43207 this.elementStyle = "padding-left:0;";
43210 var stack = this.stack;
43211 var slen = stack.length;
43213 if(!this.fieldTpl){
43214 var t = new Roo.Template(
43215 '<div class="x-form-item {5}">',
43216 '<label for="{0}" style="{2}">{1}{4}</label>',
43217 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
43219 '</div><div class="x-form-clear-left"></div>'
43221 t.disableFormats = true;
43223 Roo.form.Layout.prototype.fieldTpl = t;
43225 for(var i = 0; i < slen; i++) {
43226 if(stack[i].isFormField){
43227 this.renderField(stack[i]);
43229 this.renderComponent(stack[i]);
43234 this.el.createChild({cls:'x-form-clear'});
43239 renderField : function(f){
43240 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
43243 f.labelStyle||this.labelStyle||'', //2
43244 this.elementStyle||'', //3
43245 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
43246 f.itemCls||this.itemCls||'' //5
43247 ], true).getPrevSibling());
43251 renderComponent : function(c){
43252 c.render(c.isLayout ? this.el : this.el.createChild());
43255 * Adds a object form elements (using the xtype property as the factory method.)
43256 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
43257 * @param {Object} config
43259 addxtype : function(o)
43261 // create the lement.
43262 o.form = this.form;
43263 var fe = Roo.factory(o, Roo.form);
43264 this.form.allItems.push(fe);
43265 this.stack.push(fe);
43267 if (fe.isFormField) {
43268 this.form.items.add(fe);
43276 * @class Roo.form.Column
43277 * @extends Roo.form.Layout
43278 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
43280 * @param {Object} config Configuration options
43282 Roo.form.Column = function(config){
43283 Roo.form.Column.superclass.constructor.call(this, config);
43286 Roo.extend(Roo.form.Column, Roo.form.Layout, {
43288 * @cfg {Number/String} width
43289 * The fixed width of the column in pixels or CSS value (defaults to "auto")
43292 * @cfg {String/Object} autoCreate
43293 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
43297 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
43300 onRender : function(ct, position){
43301 Roo.form.Column.superclass.onRender.call(this, ct, position);
43303 this.el.setWidth(this.width);
43310 * @class Roo.form.Row
43311 * @extends Roo.form.Layout
43312 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
43314 * @param {Object} config Configuration options
43318 Roo.form.Row = function(config){
43319 Roo.form.Row.superclass.constructor.call(this, config);
43322 Roo.extend(Roo.form.Row, Roo.form.Layout, {
43324 * @cfg {Number/String} width
43325 * The fixed width of the column in pixels or CSS value (defaults to "auto")
43328 * @cfg {Number/String} height
43329 * The fixed height of the column in pixels or CSS value (defaults to "auto")
43331 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
43335 onRender : function(ct, position){
43336 //console.log('row render');
43338 var t = new Roo.Template(
43339 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
43340 '<label for="{0}" style="{2}">{1}{4}</label>',
43341 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
43345 t.disableFormats = true;
43347 Roo.form.Layout.prototype.rowTpl = t;
43349 this.fieldTpl = this.rowTpl;
43351 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
43352 var labelWidth = 100;
43354 if ((this.labelAlign != 'top')) {
43355 if (typeof this.labelWidth == 'number') {
43356 labelWidth = this.labelWidth
43358 this.padWidth = 20 + labelWidth;
43362 Roo.form.Column.superclass.onRender.call(this, ct, position);
43364 this.el.setWidth(this.width);
43367 this.el.setHeight(this.height);
43372 renderField : function(f){
43373 f.fieldEl = this.fieldTpl.append(this.el, [
43374 f.id, f.fieldLabel,
43375 f.labelStyle||this.labelStyle||'',
43376 this.elementStyle||'',
43377 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
43378 f.itemCls||this.itemCls||'',
43379 f.width ? f.width + this.padWidth : 160 + this.padWidth
43386 * @class Roo.form.FieldSet
43387 * @extends Roo.form.Layout
43388 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
43390 * @param {Object} config Configuration options
43392 Roo.form.FieldSet = function(config){
43393 Roo.form.FieldSet.superclass.constructor.call(this, config);
43396 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
43398 * @cfg {String} legend
43399 * The text to display as the legend for the FieldSet (defaults to '')
43402 * @cfg {String/Object} autoCreate
43403 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
43407 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
43410 onRender : function(ct, position){
43411 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
43413 this.setLegend(this.legend);
43418 setLegend : function(text){
43420 this.el.child('legend').update(text);
43425 * Ext JS Library 1.1.1
43426 * Copyright(c) 2006-2007, Ext JS, LLC.
43428 * Originally Released Under LGPL - original licence link has changed is not relivant.
43431 * <script type="text/javascript">
43434 * @class Roo.form.VTypes
43435 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
43438 Roo.form.VTypes = function(){
43439 // closure these in so they are only created once.
43440 var alpha = /^[a-zA-Z_]+$/;
43441 var alphanum = /^[a-zA-Z0-9_]+$/;
43442 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
43443 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
43445 // All these messages and functions are configurable
43448 * The function used to validate email addresses
43449 * @param {String} value The email address
43451 'email' : function(v){
43452 return email.test(v);
43455 * The error text to display when the email validation function returns false
43458 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
43460 * The keystroke filter mask to be applied on email input
43463 'emailMask' : /[a-z0-9_\.\-@]/i,
43466 * The function used to validate URLs
43467 * @param {String} value The URL
43469 'url' : function(v){
43470 return url.test(v);
43473 * The error text to display when the url validation function returns false
43476 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
43479 * The function used to validate alpha values
43480 * @param {String} value The value
43482 'alpha' : function(v){
43483 return alpha.test(v);
43486 * The error text to display when the alpha validation function returns false
43489 'alphaText' : 'This field should only contain letters and _',
43491 * The keystroke filter mask to be applied on alpha input
43494 'alphaMask' : /[a-z_]/i,
43497 * The function used to validate alphanumeric values
43498 * @param {String} value The value
43500 'alphanum' : function(v){
43501 return alphanum.test(v);
43504 * The error text to display when the alphanumeric validation function returns false
43507 'alphanumText' : 'This field should only contain letters, numbers and _',
43509 * The keystroke filter mask to be applied on alphanumeric input
43512 'alphanumMask' : /[a-z0-9_]/i
43514 }();//<script type="text/javascript">
43517 * @class Roo.form.FCKeditor
43518 * @extends Roo.form.TextArea
43519 * Wrapper around the FCKEditor http://www.fckeditor.net
43521 * Creates a new FCKeditor
43522 * @param {Object} config Configuration options
43524 Roo.form.FCKeditor = function(config){
43525 Roo.form.FCKeditor.superclass.constructor.call(this, config);
43528 * @event editorinit
43529 * Fired when the editor is initialized - you can add extra handlers here..
43530 * @param {FCKeditor} this
43531 * @param {Object} the FCK object.
43538 Roo.form.FCKeditor.editors = { };
43539 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
43541 //defaultAutoCreate : {
43542 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
43546 * @cfg {Object} fck options - see fck manual for details.
43551 * @cfg {Object} fck toolbar set (Basic or Default)
43553 toolbarSet : 'Basic',
43555 * @cfg {Object} fck BasePath
43557 basePath : '/fckeditor/',
43565 onRender : function(ct, position)
43568 this.defaultAutoCreate = {
43570 style:"width:300px;height:60px;",
43571 autocomplete: "off"
43574 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
43577 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
43578 if(this.preventScrollbars){
43579 this.el.setStyle("overflow", "hidden");
43581 this.el.setHeight(this.growMin);
43584 //console.log('onrender' + this.getId() );
43585 Roo.form.FCKeditor.editors[this.getId()] = this;
43588 this.replaceTextarea() ;
43592 getEditor : function() {
43593 return this.fckEditor;
43596 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
43597 * @param {Mixed} value The value to set
43601 setValue : function(value)
43603 //console.log('setValue: ' + value);
43605 if(typeof(value) == 'undefined') { // not sure why this is happending...
43608 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
43610 //if(!this.el || !this.getEditor()) {
43611 // this.value = value;
43612 //this.setValue.defer(100,this,[value]);
43616 if(!this.getEditor()) {
43620 this.getEditor().SetData(value);
43627 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
43628 * @return {Mixed} value The field value
43630 getValue : function()
43633 if (this.frame && this.frame.dom.style.display == 'none') {
43634 return Roo.form.FCKeditor.superclass.getValue.call(this);
43637 if(!this.el || !this.getEditor()) {
43639 // this.getValue.defer(100,this);
43644 var value=this.getEditor().GetData();
43645 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
43646 return Roo.form.FCKeditor.superclass.getValue.call(this);
43652 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
43653 * @return {Mixed} value The field value
43655 getRawValue : function()
43657 if (this.frame && this.frame.dom.style.display == 'none') {
43658 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
43661 if(!this.el || !this.getEditor()) {
43662 //this.getRawValue.defer(100,this);
43669 var value=this.getEditor().GetData();
43670 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
43671 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
43675 setSize : function(w,h) {
43679 //if (this.frame && this.frame.dom.style.display == 'none') {
43680 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43683 //if(!this.el || !this.getEditor()) {
43684 // this.setSize.defer(100,this, [w,h]);
43690 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43692 this.frame.dom.setAttribute('width', w);
43693 this.frame.dom.setAttribute('height', h);
43694 this.frame.setSize(w,h);
43698 toggleSourceEdit : function(value) {
43702 this.el.dom.style.display = value ? '' : 'none';
43703 this.frame.dom.style.display = value ? 'none' : '';
43708 focus: function(tag)
43710 if (this.frame.dom.style.display == 'none') {
43711 return Roo.form.FCKeditor.superclass.focus.call(this);
43713 if(!this.el || !this.getEditor()) {
43714 this.focus.defer(100,this, [tag]);
43721 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
43722 this.getEditor().Focus();
43724 if (!this.getEditor().Selection.GetSelection()) {
43725 this.focus.defer(100,this, [tag]);
43730 var r = this.getEditor().EditorDocument.createRange();
43731 r.setStart(tgs[0],0);
43732 r.setEnd(tgs[0],0);
43733 this.getEditor().Selection.GetSelection().removeAllRanges();
43734 this.getEditor().Selection.GetSelection().addRange(r);
43735 this.getEditor().Focus();
43742 replaceTextarea : function()
43744 if ( document.getElementById( this.getId() + '___Frame' ) )
43746 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
43748 // We must check the elements firstly using the Id and then the name.
43749 var oTextarea = document.getElementById( this.getId() );
43751 var colElementsByName = document.getElementsByName( this.getId() ) ;
43753 oTextarea.style.display = 'none' ;
43755 if ( oTextarea.tabIndex ) {
43756 this.TabIndex = oTextarea.tabIndex ;
43759 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
43760 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
43761 this.frame = Roo.get(this.getId() + '___Frame')
43764 _getConfigHtml : function()
43768 for ( var o in this.fckconfig ) {
43769 sConfig += sConfig.length > 0 ? '&' : '';
43770 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
43773 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
43777 _getIFrameHtml : function()
43779 var sFile = 'fckeditor.html' ;
43780 /* no idea what this is about..
43783 if ( (/fcksource=true/i).test( window.top.location.search ) )
43784 sFile = 'fckeditor.original.html' ;
43789 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
43790 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
43793 var html = '<iframe id="' + this.getId() +
43794 '___Frame" src="' + sLink +
43795 '" width="' + this.width +
43796 '" height="' + this.height + '"' +
43797 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
43798 ' frameborder="0" scrolling="no"></iframe>' ;
43803 _insertHtmlBefore : function( html, element )
43805 if ( element.insertAdjacentHTML ) {
43807 element.insertAdjacentHTML( 'beforeBegin', html ) ;
43809 var oRange = document.createRange() ;
43810 oRange.setStartBefore( element ) ;
43811 var oFragment = oRange.createContextualFragment( html );
43812 element.parentNode.insertBefore( oFragment, element ) ;
43825 //Roo.reg('fckeditor', Roo.form.FCKeditor);
43827 function FCKeditor_OnComplete(editorInstance){
43828 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
43829 f.fckEditor = editorInstance;
43830 //console.log("loaded");
43831 f.fireEvent('editorinit', f, editorInstance);
43851 //<script type="text/javascript">
43853 * @class Roo.form.GridField
43854 * @extends Roo.form.Field
43855 * Embed a grid (or editable grid into a form)
43858 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
43860 * xgrid.store = Roo.data.Store
43861 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
43862 * xgrid.store.reader = Roo.data.JsonReader
43866 * Creates a new GridField
43867 * @param {Object} config Configuration options
43869 Roo.form.GridField = function(config){
43870 Roo.form.GridField.superclass.constructor.call(this, config);
43874 Roo.extend(Roo.form.GridField, Roo.form.Field, {
43876 * @cfg {Number} width - used to restrict width of grid..
43880 * @cfg {Number} height - used to restrict height of grid..
43884 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
43890 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43891 * {tag: "input", type: "checkbox", autocomplete: "off"})
43893 // defaultAutoCreate : { tag: 'div' },
43894 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43896 * @cfg {String} addTitle Text to include for adding a title.
43900 onResize : function(){
43901 Roo.form.Field.superclass.onResize.apply(this, arguments);
43904 initEvents : function(){
43905 // Roo.form.Checkbox.superclass.initEvents.call(this);
43906 // has no events...
43911 getResizeEl : function(){
43915 getPositionEl : function(){
43920 onRender : function(ct, position){
43922 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
43923 var style = this.style;
43926 Roo.form.GridField.superclass.onRender.call(this, ct, position);
43927 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
43928 this.viewEl = this.wrap.createChild({ tag: 'div' });
43930 this.viewEl.applyStyles(style);
43933 this.viewEl.setWidth(this.width);
43936 this.viewEl.setHeight(this.height);
43938 //if(this.inputValue !== undefined){
43939 //this.setValue(this.value);
43942 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
43945 this.grid.render();
43946 this.grid.getDataSource().on('remove', this.refreshValue, this);
43947 this.grid.getDataSource().on('update', this.refreshValue, this);
43948 this.grid.on('afteredit', this.refreshValue, this);
43954 * Sets the value of the item.
43955 * @param {String} either an object or a string..
43957 setValue : function(v){
43959 v = v || []; // empty set..
43960 // this does not seem smart - it really only affects memoryproxy grids..
43961 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
43962 var ds = this.grid.getDataSource();
43963 // assumes a json reader..
43965 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
43966 ds.loadData( data);
43968 // clear selection so it does not get stale.
43969 if (this.grid.sm) {
43970 this.grid.sm.clearSelections();
43973 Roo.form.GridField.superclass.setValue.call(this, v);
43974 this.refreshValue();
43975 // should load data in the grid really....
43979 refreshValue: function() {
43981 this.grid.getDataSource().each(function(r) {
43984 this.el.dom.value = Roo.encode(val);
43992 * Ext JS Library 1.1.1
43993 * Copyright(c) 2006-2007, Ext JS, LLC.
43995 * Originally Released Under LGPL - original licence link has changed is not relivant.
43998 * <script type="text/javascript">
44001 * @class Roo.form.DisplayField
44002 * @extends Roo.form.Field
44003 * A generic Field to display non-editable data.
44005 * Creates a new Display Field item.
44006 * @param {Object} config Configuration options
44008 Roo.form.DisplayField = function(config){
44009 Roo.form.DisplayField.superclass.constructor.call(this, config);
44013 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
44014 inputType: 'hidden',
44020 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44022 focusClass : undefined,
44024 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44026 fieldClass: 'x-form-field',
44029 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
44031 valueRenderer: undefined,
44035 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44036 * {tag: "input", type: "checkbox", autocomplete: "off"})
44039 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
44041 onResize : function(){
44042 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
44046 initEvents : function(){
44047 // Roo.form.Checkbox.superclass.initEvents.call(this);
44048 // has no events...
44053 getResizeEl : function(){
44057 getPositionEl : function(){
44062 onRender : function(ct, position){
44064 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
44065 //if(this.inputValue !== undefined){
44066 this.wrap = this.el.wrap();
44068 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
44070 if (this.bodyStyle) {
44071 this.viewEl.applyStyles(this.bodyStyle);
44073 //this.viewEl.setStyle('padding', '2px');
44075 this.setValue(this.value);
44080 initValue : Roo.emptyFn,
44085 onClick : function(){
44090 * Sets the checked state of the checkbox.
44091 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
44093 setValue : function(v){
44095 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
44096 // this might be called before we have a dom element..
44097 if (!this.viewEl) {
44100 this.viewEl.dom.innerHTML = html;
44101 Roo.form.DisplayField.superclass.setValue.call(this, v);
44111 * @class Roo.form.DayPicker
44112 * @extends Roo.form.Field
44113 * A Day picker show [M] [T] [W] ....
44115 * Creates a new Day Picker
44116 * @param {Object} config Configuration options
44118 Roo.form.DayPicker= function(config){
44119 Roo.form.DayPicker.superclass.constructor.call(this, config);
44123 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
44125 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44127 focusClass : undefined,
44129 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44131 fieldClass: "x-form-field",
44134 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44135 * {tag: "input", type: "checkbox", autocomplete: "off"})
44137 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
44140 actionMode : 'viewEl',
44144 inputType : 'hidden',
44147 inputElement: false, // real input element?
44148 basedOn: false, // ????
44150 isFormField: true, // not sure where this is needed!!!!
44152 onResize : function(){
44153 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
44154 if(!this.boxLabel){
44155 this.el.alignTo(this.wrap, 'c-c');
44159 initEvents : function(){
44160 Roo.form.Checkbox.superclass.initEvents.call(this);
44161 this.el.on("click", this.onClick, this);
44162 this.el.on("change", this.onClick, this);
44166 getResizeEl : function(){
44170 getPositionEl : function(){
44176 onRender : function(ct, position){
44177 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44179 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
44181 var r1 = '<table><tr>';
44182 var r2 = '<tr class="x-form-daypick-icons">';
44183 for (var i=0; i < 7; i++) {
44184 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
44185 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
44188 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
44189 viewEl.select('img').on('click', this.onClick, this);
44190 this.viewEl = viewEl;
44193 // this will not work on Chrome!!!
44194 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44195 this.el.on('propertychange', this.setFromHidden, this); //ie
44203 initValue : Roo.emptyFn,
44206 * Returns the checked state of the checkbox.
44207 * @return {Boolean} True if checked, else false
44209 getValue : function(){
44210 return this.el.dom.value;
44215 onClick : function(e){
44216 //this.setChecked(!this.checked);
44217 Roo.get(e.target).toggleClass('x-menu-item-checked');
44218 this.refreshValue();
44219 //if(this.el.dom.checked != this.checked){
44220 // this.setValue(this.el.dom.checked);
44225 refreshValue : function()
44228 this.viewEl.select('img',true).each(function(e,i,n) {
44229 val += e.is(".x-menu-item-checked") ? String(n) : '';
44231 this.setValue(val, true);
44235 * Sets the checked state of the checkbox.
44236 * On is always based on a string comparison between inputValue and the param.
44237 * @param {Boolean/String} value - the value to set
44238 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
44240 setValue : function(v,suppressEvent){
44241 if (!this.el.dom) {
44244 var old = this.el.dom.value ;
44245 this.el.dom.value = v;
44246 if (suppressEvent) {
44250 // update display..
44251 this.viewEl.select('img',true).each(function(e,i,n) {
44253 var on = e.is(".x-menu-item-checked");
44254 var newv = v.indexOf(String(n)) > -1;
44256 e.toggleClass('x-menu-item-checked');
44262 this.fireEvent('change', this, v, old);
44267 // handle setting of hidden value by some other method!!?!?
44268 setFromHidden: function()
44273 //console.log("SET FROM HIDDEN");
44274 //alert('setFrom hidden');
44275 this.setValue(this.el.dom.value);
44278 onDestroy : function()
44281 Roo.get(this.viewEl).remove();
44284 Roo.form.DayPicker.superclass.onDestroy.call(this);
44288 * RooJS Library 1.1.1
44289 * Copyright(c) 2008-2011 Alan Knowles
44296 * @class Roo.form.ComboCheck
44297 * @extends Roo.form.ComboBox
44298 * A combobox for multiple select items.
44300 * FIXME - could do with a reset button..
44303 * Create a new ComboCheck
44304 * @param {Object} config Configuration options
44306 Roo.form.ComboCheck = function(config){
44307 Roo.form.ComboCheck.superclass.constructor.call(this, config);
44308 // should verify some data...
44310 // hiddenName = required..
44311 // displayField = required
44312 // valudField == required
44313 var req= [ 'hiddenName', 'displayField', 'valueField' ];
44315 Roo.each(req, function(e) {
44316 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
44317 throw "Roo.form.ComboCheck : missing value for: " + e;
44324 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
44329 selectedClass: 'x-menu-item-checked',
44332 onRender : function(ct, position){
44338 var cls = 'x-combo-list';
44341 this.tpl = new Roo.Template({
44342 html : '<div class="'+cls+'-item x-menu-check-item">' +
44343 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
44344 '<span>{' + this.displayField + '}</span>' +
44351 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
44352 this.view.singleSelect = false;
44353 this.view.multiSelect = true;
44354 this.view.toggleSelect = true;
44355 this.pageTb.add(new Roo.Toolbar.Fill(), {
44358 handler: function()
44365 onViewOver : function(e, t){
44371 onViewClick : function(doFocus,index){
44375 select: function () {
44376 //Roo.log("SELECT CALLED");
44379 selectByValue : function(xv, scrollIntoView){
44380 var ar = this.getValueArray();
44383 Roo.each(ar, function(v) {
44384 if(v === undefined || v === null){
44387 var r = this.findRecord(this.valueField, v);
44389 sels.push(this.store.indexOf(r))
44393 this.view.select(sels);
44399 onSelect : function(record, index){
44400 // Roo.log("onselect Called");
44401 // this is only called by the clear button now..
44402 this.view.clearSelections();
44403 this.setValue('[]');
44404 if (this.value != this.valueBefore) {
44405 this.fireEvent('change', this, this.value, this.valueBefore);
44408 getValueArray : function()
44413 //Roo.log(this.value);
44414 if (typeof(this.value) == 'undefined') {
44417 var ar = Roo.decode(this.value);
44418 return ar instanceof Array ? ar : []; //?? valid?
44421 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
44426 expand : function ()
44428 Roo.form.ComboCheck.superclass.expand.call(this);
44429 this.valueBefore = this.value;
44434 collapse : function(){
44435 Roo.form.ComboCheck.superclass.collapse.call(this);
44436 var sl = this.view.getSelectedIndexes();
44437 var st = this.store;
44441 Roo.each(sl, function(i) {
44443 nv.push(r.get(this.valueField));
44445 this.setValue(Roo.encode(nv));
44446 if (this.value != this.valueBefore) {
44448 this.fireEvent('change', this, this.value, this.valueBefore);
44453 setValue : function(v){
44457 var vals = this.getValueArray();
44459 Roo.each(vals, function(k) {
44460 var r = this.findRecord(this.valueField, k);
44462 tv.push(r.data[this.displayField]);
44463 }else if(this.valueNotFoundText !== undefined){
44464 tv.push( this.valueNotFoundText );
44469 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
44470 this.hiddenField.value = v;
44474 });//<script type="text/javasscript">
44478 * @class Roo.DDView
44479 * A DnD enabled version of Roo.View.
44480 * @param {Element/String} container The Element in which to create the View.
44481 * @param {String} tpl The template string used to create the markup for each element of the View
44482 * @param {Object} config The configuration properties. These include all the config options of
44483 * {@link Roo.View} plus some specific to this class.<br>
44485 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
44486 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
44488 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
44489 .x-view-drag-insert-above {
44490 border-top:1px dotted #3366cc;
44492 .x-view-drag-insert-below {
44493 border-bottom:1px dotted #3366cc;
44499 Roo.DDView = function(container, tpl, config) {
44500 Roo.DDView.superclass.constructor.apply(this, arguments);
44501 this.getEl().setStyle("outline", "0px none");
44502 this.getEl().unselectable();
44503 if (this.dragGroup) {
44504 this.setDraggable(this.dragGroup.split(","));
44506 if (this.dropGroup) {
44507 this.setDroppable(this.dropGroup.split(","));
44509 if (this.deletable) {
44510 this.setDeletable();
44512 this.isDirtyFlag = false;
44518 Roo.extend(Roo.DDView, Roo.View, {
44519 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
44520 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
44521 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
44522 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
44526 reset: Roo.emptyFn,
44528 clearInvalid: Roo.form.Field.prototype.clearInvalid,
44530 validate: function() {
44534 destroy: function() {
44535 this.purgeListeners();
44536 this.getEl.removeAllListeners();
44537 this.getEl().remove();
44538 if (this.dragZone) {
44539 if (this.dragZone.destroy) {
44540 this.dragZone.destroy();
44543 if (this.dropZone) {
44544 if (this.dropZone.destroy) {
44545 this.dropZone.destroy();
44550 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
44551 getName: function() {
44555 /** Loads the View from a JSON string representing the Records to put into the Store. */
44556 setValue: function(v) {
44558 throw "DDView.setValue(). DDView must be constructed with a valid Store";
44561 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
44562 this.store.proxy = new Roo.data.MemoryProxy(data);
44566 /** @return {String} a parenthesised list of the ids of the Records in the View. */
44567 getValue: function() {
44569 this.store.each(function(rec) {
44570 result += rec.id + ',';
44572 return result.substr(0, result.length - 1) + ')';
44575 getIds: function() {
44576 var i = 0, result = new Array(this.store.getCount());
44577 this.store.each(function(rec) {
44578 result[i++] = rec.id;
44583 isDirty: function() {
44584 return this.isDirtyFlag;
44588 * Part of the Roo.dd.DropZone interface. If no target node is found, the
44589 * whole Element becomes the target, and this causes the drop gesture to append.
44591 getTargetFromEvent : function(e) {
44592 var target = e.getTarget();
44593 while ((target !== null) && (target.parentNode != this.el.dom)) {
44594 target = target.parentNode;
44597 target = this.el.dom.lastChild || this.el.dom;
44603 * Create the drag data which consists of an object which has the property "ddel" as
44604 * the drag proxy element.
44606 getDragData : function(e) {
44607 var target = this.findItemFromChild(e.getTarget());
44609 this.handleSelection(e);
44610 var selNodes = this.getSelectedNodes();
44613 copy: this.copy || (this.allowCopy && e.ctrlKey),
44617 var selectedIndices = this.getSelectedIndexes();
44618 for (var i = 0; i < selectedIndices.length; i++) {
44619 dragData.records.push(this.store.getAt(selectedIndices[i]));
44621 if (selNodes.length == 1) {
44622 dragData.ddel = target.cloneNode(true); // the div element
44624 var div = document.createElement('div'); // create the multi element drag "ghost"
44625 div.className = 'multi-proxy';
44626 for (var i = 0, len = selNodes.length; i < len; i++) {
44627 div.appendChild(selNodes[i].cloneNode(true));
44629 dragData.ddel = div;
44631 //console.log(dragData)
44632 //console.log(dragData.ddel.innerHTML)
44635 //console.log('nodragData')
44639 /** Specify to which ddGroup items in this DDView may be dragged. */
44640 setDraggable: function(ddGroup) {
44641 if (ddGroup instanceof Array) {
44642 Roo.each(ddGroup, this.setDraggable, this);
44645 if (this.dragZone) {
44646 this.dragZone.addToGroup(ddGroup);
44648 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
44649 containerScroll: true,
44653 // Draggability implies selection. DragZone's mousedown selects the element.
44654 if (!this.multiSelect) { this.singleSelect = true; }
44656 // Wire the DragZone's handlers up to methods in *this*
44657 this.dragZone.getDragData = this.getDragData.createDelegate(this);
44661 /** Specify from which ddGroup this DDView accepts drops. */
44662 setDroppable: function(ddGroup) {
44663 if (ddGroup instanceof Array) {
44664 Roo.each(ddGroup, this.setDroppable, this);
44667 if (this.dropZone) {
44668 this.dropZone.addToGroup(ddGroup);
44670 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
44671 containerScroll: true,
44675 // Wire the DropZone's handlers up to methods in *this*
44676 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
44677 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
44678 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
44679 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
44680 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
44684 /** Decide whether to drop above or below a View node. */
44685 getDropPoint : function(e, n, dd){
44686 if (n == this.el.dom) { return "above"; }
44687 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
44688 var c = t + (b - t) / 2;
44689 var y = Roo.lib.Event.getPageY(e);
44697 onNodeEnter : function(n, dd, e, data){
44701 onNodeOver : function(n, dd, e, data){
44702 var pt = this.getDropPoint(e, n, dd);
44703 // set the insert point style on the target node
44704 var dragElClass = this.dropNotAllowed;
44707 if (pt == "above"){
44708 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
44709 targetElClass = "x-view-drag-insert-above";
44711 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
44712 targetElClass = "x-view-drag-insert-below";
44714 if (this.lastInsertClass != targetElClass){
44715 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
44716 this.lastInsertClass = targetElClass;
44719 return dragElClass;
44722 onNodeOut : function(n, dd, e, data){
44723 this.removeDropIndicators(n);
44726 onNodeDrop : function(n, dd, e, data){
44727 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
44730 var pt = this.getDropPoint(e, n, dd);
44731 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
44732 if (pt == "below") { insertAt++; }
44733 for (var i = 0; i < data.records.length; i++) {
44734 var r = data.records[i];
44735 var dup = this.store.getById(r.id);
44736 if (dup && (dd != this.dragZone)) {
44737 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
44740 this.store.insert(insertAt++, r.copy());
44742 data.source.isDirtyFlag = true;
44744 this.store.insert(insertAt++, r);
44746 this.isDirtyFlag = true;
44749 this.dragZone.cachedTarget = null;
44753 removeDropIndicators : function(n){
44755 Roo.fly(n).removeClass([
44756 "x-view-drag-insert-above",
44757 "x-view-drag-insert-below"]);
44758 this.lastInsertClass = "_noclass";
44763 * Utility method. Add a delete option to the DDView's context menu.
44764 * @param {String} imageUrl The URL of the "delete" icon image.
44766 setDeletable: function(imageUrl) {
44767 if (!this.singleSelect && !this.multiSelect) {
44768 this.singleSelect = true;
44770 var c = this.getContextMenu();
44771 this.contextMenu.on("itemclick", function(item) {
44774 this.remove(this.getSelectedIndexes());
44778 this.contextMenu.add({
44785 /** Return the context menu for this DDView. */
44786 getContextMenu: function() {
44787 if (!this.contextMenu) {
44788 // Create the View's context menu
44789 this.contextMenu = new Roo.menu.Menu({
44790 id: this.id + "-contextmenu"
44792 this.el.on("contextmenu", this.showContextMenu, this);
44794 return this.contextMenu;
44797 disableContextMenu: function() {
44798 if (this.contextMenu) {
44799 this.el.un("contextmenu", this.showContextMenu, this);
44803 showContextMenu: function(e, item) {
44804 item = this.findItemFromChild(e.getTarget());
44807 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
44808 this.contextMenu.showAt(e.getXY());
44813 * Remove {@link Roo.data.Record}s at the specified indices.
44814 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
44816 remove: function(selectedIndices) {
44817 selectedIndices = [].concat(selectedIndices);
44818 for (var i = 0; i < selectedIndices.length; i++) {
44819 var rec = this.store.getAt(selectedIndices[i]);
44820 this.store.remove(rec);
44825 * Double click fires the event, but also, if this is draggable, and there is only one other
44826 * related DropZone, it transfers the selected node.
44828 onDblClick : function(e){
44829 var item = this.findItemFromChild(e.getTarget());
44831 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
44834 if (this.dragGroup) {
44835 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
44836 while (targets.indexOf(this.dropZone) > -1) {
44837 targets.remove(this.dropZone);
44839 if (targets.length == 1) {
44840 this.dragZone.cachedTarget = null;
44841 var el = Roo.get(targets[0].getEl());
44842 var box = el.getBox(true);
44843 targets[0].onNodeDrop(el.dom, {
44845 xy: [box.x, box.y + box.height - 1]
44846 }, null, this.getDragData(e));
44852 handleSelection: function(e) {
44853 this.dragZone.cachedTarget = null;
44854 var item = this.findItemFromChild(e.getTarget());
44856 this.clearSelections(true);
44859 if (item && (this.multiSelect || this.singleSelect)){
44860 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
44861 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
44862 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
44863 this.unselect(item);
44865 this.select(item, this.multiSelect && e.ctrlKey);
44866 this.lastSelection = item;
44871 onItemClick : function(item, index, e){
44872 if(this.fireEvent("beforeclick", this, index, item, e) === false){
44878 unselect : function(nodeInfo, suppressEvent){
44879 var node = this.getNode(nodeInfo);
44880 if(node && this.isSelected(node)){
44881 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
44882 Roo.fly(node).removeClass(this.selectedClass);
44883 this.selections.remove(node);
44884 if(!suppressEvent){
44885 this.fireEvent("selectionchange", this, this.selections);
44893 * Ext JS Library 1.1.1
44894 * Copyright(c) 2006-2007, Ext JS, LLC.
44896 * Originally Released Under LGPL - original licence link has changed is not relivant.
44899 * <script type="text/javascript">
44903 * @class Roo.LayoutManager
44904 * @extends Roo.util.Observable
44905 * Base class for layout managers.
44907 Roo.LayoutManager = function(container, config){
44908 Roo.LayoutManager.superclass.constructor.call(this);
44909 this.el = Roo.get(container);
44910 // ie scrollbar fix
44911 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
44912 document.body.scroll = "no";
44913 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
44914 this.el.position('relative');
44916 this.id = this.el.id;
44917 this.el.addClass("x-layout-container");
44918 /** false to disable window resize monitoring @type Boolean */
44919 this.monitorWindowResize = true;
44924 * Fires when a layout is performed.
44925 * @param {Roo.LayoutManager} this
44929 * @event regionresized
44930 * Fires when the user resizes a region.
44931 * @param {Roo.LayoutRegion} region The resized region
44932 * @param {Number} newSize The new size (width for east/west, height for north/south)
44934 "regionresized" : true,
44936 * @event regioncollapsed
44937 * Fires when a region is collapsed.
44938 * @param {Roo.LayoutRegion} region The collapsed region
44940 "regioncollapsed" : true,
44942 * @event regionexpanded
44943 * Fires when a region is expanded.
44944 * @param {Roo.LayoutRegion} region The expanded region
44946 "regionexpanded" : true
44948 this.updating = false;
44949 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
44952 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
44954 * Returns true if this layout is currently being updated
44955 * @return {Boolean}
44957 isUpdating : function(){
44958 return this.updating;
44962 * Suspend the LayoutManager from doing auto-layouts while
44963 * making multiple add or remove calls
44965 beginUpdate : function(){
44966 this.updating = true;
44970 * Restore auto-layouts and optionally disable the manager from performing a layout
44971 * @param {Boolean} noLayout true to disable a layout update
44973 endUpdate : function(noLayout){
44974 this.updating = false;
44980 layout: function(){
44984 onRegionResized : function(region, newSize){
44985 this.fireEvent("regionresized", region, newSize);
44989 onRegionCollapsed : function(region){
44990 this.fireEvent("regioncollapsed", region);
44993 onRegionExpanded : function(region){
44994 this.fireEvent("regionexpanded", region);
44998 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
44999 * performs box-model adjustments.
45000 * @return {Object} The size as an object {width: (the width), height: (the height)}
45002 getViewSize : function(){
45004 if(this.el.dom != document.body){
45005 size = this.el.getSize();
45007 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
45009 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
45010 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
45015 * Returns the Element this layout is bound to.
45016 * @return {Roo.Element}
45018 getEl : function(){
45023 * Returns the specified region.
45024 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
45025 * @return {Roo.LayoutRegion}
45027 getRegion : function(target){
45028 return this.regions[target.toLowerCase()];
45031 onWindowResize : function(){
45032 if(this.monitorWindowResize){
45038 * Ext JS Library 1.1.1
45039 * Copyright(c) 2006-2007, Ext JS, LLC.
45041 * Originally Released Under LGPL - original licence link has changed is not relivant.
45044 * <script type="text/javascript">
45047 * @class Roo.BorderLayout
45048 * @extends Roo.LayoutManager
45049 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
45050 * please see: <br><br>
45051 * <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>
45052 * <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>
45055 var layout = new Roo.BorderLayout(document.body, {
45089 preferredTabWidth: 150
45094 var CP = Roo.ContentPanel;
45096 layout.beginUpdate();
45097 layout.add("north", new CP("north", "North"));
45098 layout.add("south", new CP("south", {title: "South", closable: true}));
45099 layout.add("west", new CP("west", {title: "West"}));
45100 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
45101 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
45102 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
45103 layout.getRegion("center").showPanel("center1");
45104 layout.endUpdate();
45107 <b>The container the layout is rendered into can be either the body element or any other element.
45108 If it is not the body element, the container needs to either be an absolute positioned element,
45109 or you will need to add "position:relative" to the css of the container. You will also need to specify
45110 the container size if it is not the body element.</b>
45113 * Create a new BorderLayout
45114 * @param {String/HTMLElement/Element} container The container this layout is bound to
45115 * @param {Object} config Configuration options
45117 Roo.BorderLayout = function(container, config){
45118 config = config || {};
45119 Roo.BorderLayout.superclass.constructor.call(this, container, config);
45120 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
45121 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
45122 var target = this.factory.validRegions[i];
45123 if(config[target]){
45124 this.addRegion(target, config[target]);
45129 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
45131 * Creates and adds a new region if it doesn't already exist.
45132 * @param {String} target The target region key (north, south, east, west or center).
45133 * @param {Object} config The regions config object
45134 * @return {BorderLayoutRegion} The new region
45136 addRegion : function(target, config){
45137 if(!this.regions[target]){
45138 var r = this.factory.create(target, this, config);
45139 this.bindRegion(target, r);
45141 return this.regions[target];
45145 bindRegion : function(name, r){
45146 this.regions[name] = r;
45147 r.on("visibilitychange", this.layout, this);
45148 r.on("paneladded", this.layout, this);
45149 r.on("panelremoved", this.layout, this);
45150 r.on("invalidated", this.layout, this);
45151 r.on("resized", this.onRegionResized, this);
45152 r.on("collapsed", this.onRegionCollapsed, this);
45153 r.on("expanded", this.onRegionExpanded, this);
45157 * Performs a layout update.
45159 layout : function(){
45160 if(this.updating) return;
45161 var size = this.getViewSize();
45162 var w = size.width;
45163 var h = size.height;
45168 //var x = 0, y = 0;
45170 var rs = this.regions;
45171 var north = rs["north"];
45172 var south = rs["south"];
45173 var west = rs["west"];
45174 var east = rs["east"];
45175 var center = rs["center"];
45176 //if(this.hideOnLayout){ // not supported anymore
45177 //c.el.setStyle("display", "none");
45179 if(north && north.isVisible()){
45180 var b = north.getBox();
45181 var m = north.getMargins();
45182 b.width = w - (m.left+m.right);
45185 centerY = b.height + b.y + m.bottom;
45186 centerH -= centerY;
45187 north.updateBox(this.safeBox(b));
45189 if(south && south.isVisible()){
45190 var b = south.getBox();
45191 var m = south.getMargins();
45192 b.width = w - (m.left+m.right);
45194 var totalHeight = (b.height + m.top + m.bottom);
45195 b.y = h - totalHeight + m.top;
45196 centerH -= totalHeight;
45197 south.updateBox(this.safeBox(b));
45199 if(west && west.isVisible()){
45200 var b = west.getBox();
45201 var m = west.getMargins();
45202 b.height = centerH - (m.top+m.bottom);
45204 b.y = centerY + m.top;
45205 var totalWidth = (b.width + m.left + m.right);
45206 centerX += totalWidth;
45207 centerW -= totalWidth;
45208 west.updateBox(this.safeBox(b));
45210 if(east && east.isVisible()){
45211 var b = east.getBox();
45212 var m = east.getMargins();
45213 b.height = centerH - (m.top+m.bottom);
45214 var totalWidth = (b.width + m.left + m.right);
45215 b.x = w - totalWidth + m.left;
45216 b.y = centerY + m.top;
45217 centerW -= totalWidth;
45218 east.updateBox(this.safeBox(b));
45221 var m = center.getMargins();
45223 x: centerX + m.left,
45224 y: centerY + m.top,
45225 width: centerW - (m.left+m.right),
45226 height: centerH - (m.top+m.bottom)
45228 //if(this.hideOnLayout){
45229 //center.el.setStyle("display", "block");
45231 center.updateBox(this.safeBox(centerBox));
45234 this.fireEvent("layout", this);
45238 safeBox : function(box){
45239 box.width = Math.max(0, box.width);
45240 box.height = Math.max(0, box.height);
45245 * Adds a ContentPanel (or subclass) to this layout.
45246 * @param {String} target The target region key (north, south, east, west or center).
45247 * @param {Roo.ContentPanel} panel The panel to add
45248 * @return {Roo.ContentPanel} The added panel
45250 add : function(target, panel){
45252 target = target.toLowerCase();
45253 return this.regions[target].add(panel);
45257 * Remove a ContentPanel (or subclass) to this layout.
45258 * @param {String} target The target region key (north, south, east, west or center).
45259 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
45260 * @return {Roo.ContentPanel} The removed panel
45262 remove : function(target, panel){
45263 target = target.toLowerCase();
45264 return this.regions[target].remove(panel);
45268 * Searches all regions for a panel with the specified id
45269 * @param {String} panelId
45270 * @return {Roo.ContentPanel} The panel or null if it wasn't found
45272 findPanel : function(panelId){
45273 var rs = this.regions;
45274 for(var target in rs){
45275 if(typeof rs[target] != "function"){
45276 var p = rs[target].getPanel(panelId);
45286 * Searches all regions for a panel with the specified id and activates (shows) it.
45287 * @param {String/ContentPanel} panelId The panels id or the panel itself
45288 * @return {Roo.ContentPanel} The shown panel or null
45290 showPanel : function(panelId) {
45291 var rs = this.regions;
45292 for(var target in rs){
45293 var r = rs[target];
45294 if(typeof r != "function"){
45295 if(r.hasPanel(panelId)){
45296 return r.showPanel(panelId);
45304 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
45305 * @param {Roo.state.Provider} provider (optional) An alternate state provider
45307 restoreState : function(provider){
45309 provider = Roo.state.Manager;
45311 var sm = new Roo.LayoutStateManager();
45312 sm.init(this, provider);
45316 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
45317 * object should contain properties for each region to add ContentPanels to, and each property's value should be
45318 * a valid ContentPanel config object. Example:
45320 // Create the main layout
45321 var layout = new Roo.BorderLayout('main-ct', {
45332 // Create and add multiple ContentPanels at once via configs
45335 id: 'source-files',
45337 title:'Ext Source Files',
45350 * @param {Object} regions An object containing ContentPanel configs by region name
45352 batchAdd : function(regions){
45353 this.beginUpdate();
45354 for(var rname in regions){
45355 var lr = this.regions[rname];
45357 this.addTypedPanels(lr, regions[rname]);
45364 addTypedPanels : function(lr, ps){
45365 if(typeof ps == 'string'){
45366 lr.add(new Roo.ContentPanel(ps));
45368 else if(ps instanceof Array){
45369 for(var i =0, len = ps.length; i < len; i++){
45370 this.addTypedPanels(lr, ps[i]);
45373 else if(!ps.events){ // raw config?
45375 delete ps.el; // prevent conflict
45376 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
45378 else { // panel object assumed!
45383 * Adds a xtype elements to the layout.
45387 xtype : 'ContentPanel',
45394 xtype : 'NestedLayoutPanel',
45400 items : [ ... list of content panels or nested layout panels.. ]
45404 * @param {Object} cfg Xtype definition of item to add.
45406 addxtype : function(cfg)
45408 // basically accepts a pannel...
45409 // can accept a layout region..!?!?
45410 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
45412 if (!cfg.xtype.match(/Panel$/)) {
45417 if (typeof(cfg.region) == 'undefined') {
45418 Roo.log("Failed to add Panel, region was not set");
45422 var region = cfg.region;
45428 xitems = cfg.items;
45435 case 'ContentPanel': // ContentPanel (el, cfg)
45436 case 'ScrollPanel': // ContentPanel (el, cfg)
45437 if(cfg.autoCreate) {
45438 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
45440 var el = this.el.createChild();
45441 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
45444 this.add(region, ret);
45448 case 'TreePanel': // our new panel!
45449 cfg.el = this.el.createChild();
45450 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
45451 this.add(region, ret);
45454 case 'NestedLayoutPanel':
45455 // create a new Layout (which is a Border Layout...
45456 var el = this.el.createChild();
45457 var clayout = cfg.layout;
45459 clayout.items = clayout.items || [];
45460 // replace this exitems with the clayout ones..
45461 xitems = clayout.items;
45464 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
45465 cfg.background = false;
45467 var layout = new Roo.BorderLayout(el, clayout);
45469 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
45470 //console.log('adding nested layout panel ' + cfg.toSource());
45471 this.add(region, ret);
45472 nb = {}; /// find first...
45477 // needs grid and region
45479 //var el = this.getRegion(region).el.createChild();
45480 var el = this.el.createChild();
45481 // create the grid first...
45483 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
45485 if (region == 'center' && this.active ) {
45486 cfg.background = false;
45488 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
45490 this.add(region, ret);
45491 if (cfg.background) {
45492 ret.on('activate', function(gp) {
45493 if (!gp.grid.rendered) {
45506 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
45508 // GridPanel (grid, cfg)
45511 this.beginUpdate();
45515 Roo.each(xitems, function(i) {
45516 region = nb && i.region ? i.region : false;
45518 var add = ret.addxtype(i);
45521 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
45522 if (!i.background) {
45523 abn[region] = nb[region] ;
45530 // make the last non-background panel active..
45531 //if (nb) { Roo.log(abn); }
45534 for(var r in abn) {
45535 region = this.getRegion(r);
45537 // tried using nb[r], but it does not work..
45539 region.showPanel(abn[r]);
45550 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
45551 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
45552 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
45553 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
45556 var CP = Roo.ContentPanel;
45558 var layout = Roo.BorderLayout.create({
45562 panels: [new CP("north", "North")]
45571 panels: [new CP("west", {title: "West"})]
45580 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
45589 panels: [new CP("south", {title: "South", closable: true})]
45596 preferredTabWidth: 150,
45598 new CP("center1", {title: "Close Me", closable: true}),
45599 new CP("center2", {title: "Center Panel", closable: false})
45604 layout.getRegion("center").showPanel("center1");
45609 Roo.BorderLayout.create = function(config, targetEl){
45610 var layout = new Roo.BorderLayout(targetEl || document.body, config);
45611 layout.beginUpdate();
45612 var regions = Roo.BorderLayout.RegionFactory.validRegions;
45613 for(var j = 0, jlen = regions.length; j < jlen; j++){
45614 var lr = regions[j];
45615 if(layout.regions[lr] && config[lr].panels){
45616 var r = layout.regions[lr];
45617 var ps = config[lr].panels;
45618 layout.addTypedPanels(r, ps);
45621 layout.endUpdate();
45626 Roo.BorderLayout.RegionFactory = {
45628 validRegions : ["north","south","east","west","center"],
45631 create : function(target, mgr, config){
45632 target = target.toLowerCase();
45633 if(config.lightweight || config.basic){
45634 return new Roo.BasicLayoutRegion(mgr, config, target);
45638 return new Roo.NorthLayoutRegion(mgr, config);
45640 return new Roo.SouthLayoutRegion(mgr, config);
45642 return new Roo.EastLayoutRegion(mgr, config);
45644 return new Roo.WestLayoutRegion(mgr, config);
45646 return new Roo.CenterLayoutRegion(mgr, config);
45648 throw 'Layout region "'+target+'" not supported.';
45652 * Ext JS Library 1.1.1
45653 * Copyright(c) 2006-2007, Ext JS, LLC.
45655 * Originally Released Under LGPL - original licence link has changed is not relivant.
45658 * <script type="text/javascript">
45662 * @class Roo.BasicLayoutRegion
45663 * @extends Roo.util.Observable
45664 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
45665 * and does not have a titlebar, tabs or any other features. All it does is size and position
45666 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
45668 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
45670 this.position = pos;
45673 * @scope Roo.BasicLayoutRegion
45677 * @event beforeremove
45678 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
45679 * @param {Roo.LayoutRegion} this
45680 * @param {Roo.ContentPanel} panel The panel
45681 * @param {Object} e The cancel event object
45683 "beforeremove" : true,
45685 * @event invalidated
45686 * Fires when the layout for this region is changed.
45687 * @param {Roo.LayoutRegion} this
45689 "invalidated" : true,
45691 * @event visibilitychange
45692 * Fires when this region is shown or hidden
45693 * @param {Roo.LayoutRegion} this
45694 * @param {Boolean} visibility true or false
45696 "visibilitychange" : true,
45698 * @event paneladded
45699 * Fires when a panel is added.
45700 * @param {Roo.LayoutRegion} this
45701 * @param {Roo.ContentPanel} panel The panel
45703 "paneladded" : true,
45705 * @event panelremoved
45706 * Fires when a panel is removed.
45707 * @param {Roo.LayoutRegion} this
45708 * @param {Roo.ContentPanel} panel The panel
45710 "panelremoved" : true,
45713 * Fires when this region is collapsed.
45714 * @param {Roo.LayoutRegion} this
45716 "collapsed" : true,
45719 * Fires when this region is expanded.
45720 * @param {Roo.LayoutRegion} this
45725 * Fires when this region is slid into view.
45726 * @param {Roo.LayoutRegion} this
45728 "slideshow" : true,
45731 * Fires when this region slides out of view.
45732 * @param {Roo.LayoutRegion} this
45734 "slidehide" : true,
45736 * @event panelactivated
45737 * Fires when a panel is activated.
45738 * @param {Roo.LayoutRegion} this
45739 * @param {Roo.ContentPanel} panel The activated panel
45741 "panelactivated" : true,
45744 * Fires when the user resizes this region.
45745 * @param {Roo.LayoutRegion} this
45746 * @param {Number} newSize The new size (width for east/west, height for north/south)
45750 /** A collection of panels in this region. @type Roo.util.MixedCollection */
45751 this.panels = new Roo.util.MixedCollection();
45752 this.panels.getKey = this.getPanelId.createDelegate(this);
45754 this.activePanel = null;
45755 // ensure listeners are added...
45757 if (config.listeners || config.events) {
45758 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
45759 listeners : config.listeners || {},
45760 events : config.events || {}
45764 if(skipConfig !== true){
45765 this.applyConfig(config);
45769 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
45770 getPanelId : function(p){
45774 applyConfig : function(config){
45775 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45776 this.config = config;
45781 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
45782 * the width, for horizontal (north, south) the height.
45783 * @param {Number} newSize The new width or height
45785 resizeTo : function(newSize){
45786 var el = this.el ? this.el :
45787 (this.activePanel ? this.activePanel.getEl() : null);
45789 switch(this.position){
45792 el.setWidth(newSize);
45793 this.fireEvent("resized", this, newSize);
45797 el.setHeight(newSize);
45798 this.fireEvent("resized", this, newSize);
45804 getBox : function(){
45805 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
45808 getMargins : function(){
45809 return this.margins;
45812 updateBox : function(box){
45814 var el = this.activePanel.getEl();
45815 el.dom.style.left = box.x + "px";
45816 el.dom.style.top = box.y + "px";
45817 this.activePanel.setSize(box.width, box.height);
45821 * Returns the container element for this region.
45822 * @return {Roo.Element}
45824 getEl : function(){
45825 return this.activePanel;
45829 * Returns true if this region is currently visible.
45830 * @return {Boolean}
45832 isVisible : function(){
45833 return this.activePanel ? true : false;
45836 setActivePanel : function(panel){
45837 panel = this.getPanel(panel);
45838 if(this.activePanel && this.activePanel != panel){
45839 this.activePanel.setActiveState(false);
45840 this.activePanel.getEl().setLeftTop(-10000,-10000);
45842 this.activePanel = panel;
45843 panel.setActiveState(true);
45845 panel.setSize(this.box.width, this.box.height);
45847 this.fireEvent("panelactivated", this, panel);
45848 this.fireEvent("invalidated");
45852 * Show the specified panel.
45853 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
45854 * @return {Roo.ContentPanel} The shown panel or null
45856 showPanel : function(panel){
45857 if(panel = this.getPanel(panel)){
45858 this.setActivePanel(panel);
45864 * Get the active panel for this region.
45865 * @return {Roo.ContentPanel} The active panel or null
45867 getActivePanel : function(){
45868 return this.activePanel;
45872 * Add the passed ContentPanel(s)
45873 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45874 * @return {Roo.ContentPanel} The panel added (if only one was added)
45876 add : function(panel){
45877 if(arguments.length > 1){
45878 for(var i = 0, len = arguments.length; i < len; i++) {
45879 this.add(arguments[i]);
45883 if(this.hasPanel(panel)){
45884 this.showPanel(panel);
45887 var el = panel.getEl();
45888 if(el.dom.parentNode != this.mgr.el.dom){
45889 this.mgr.el.dom.appendChild(el.dom);
45891 if(panel.setRegion){
45892 panel.setRegion(this);
45894 this.panels.add(panel);
45895 el.setStyle("position", "absolute");
45896 if(!panel.background){
45897 this.setActivePanel(panel);
45898 if(this.config.initialSize && this.panels.getCount()==1){
45899 this.resizeTo(this.config.initialSize);
45902 this.fireEvent("paneladded", this, panel);
45907 * Returns true if the panel is in this region.
45908 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45909 * @return {Boolean}
45911 hasPanel : function(panel){
45912 if(typeof panel == "object"){ // must be panel obj
45913 panel = panel.getId();
45915 return this.getPanel(panel) ? true : false;
45919 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45920 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45921 * @param {Boolean} preservePanel Overrides the config preservePanel option
45922 * @return {Roo.ContentPanel} The panel that was removed
45924 remove : function(panel, preservePanel){
45925 panel = this.getPanel(panel);
45930 this.fireEvent("beforeremove", this, panel, e);
45931 if(e.cancel === true){
45934 var panelId = panel.getId();
45935 this.panels.removeKey(panelId);
45940 * Returns the panel specified or null if it's not in this region.
45941 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45942 * @return {Roo.ContentPanel}
45944 getPanel : function(id){
45945 if(typeof id == "object"){ // must be panel obj
45948 return this.panels.get(id);
45952 * Returns this regions position (north/south/east/west/center).
45955 getPosition: function(){
45956 return this.position;
45960 * Ext JS Library 1.1.1
45961 * Copyright(c) 2006-2007, Ext JS, LLC.
45963 * Originally Released Under LGPL - original licence link has changed is not relivant.
45966 * <script type="text/javascript">
45970 * @class Roo.LayoutRegion
45971 * @extends Roo.BasicLayoutRegion
45972 * This class represents a region in a layout manager.
45973 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
45974 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
45975 * @cfg {Boolean} floatable False to disable floating (defaults to true)
45976 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
45977 * @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})
45978 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
45979 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
45980 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
45981 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
45982 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
45983 * @cfg {String} title The title for the region (overrides panel titles)
45984 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
45985 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
45986 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
45987 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
45988 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
45989 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
45990 * the space available, similar to FireFox 1.5 tabs (defaults to false)
45991 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
45992 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
45993 * @cfg {Boolean} showPin True to show a pin button
45994 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
45995 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
45996 * @cfg {Boolean} disableTabTips True to disable tab tooltips
45997 * @cfg {Number} width For East/West panels
45998 * @cfg {Number} height For North/South panels
45999 * @cfg {Boolean} split To show the splitter
46000 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
46002 Roo.LayoutRegion = function(mgr, config, pos){
46003 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
46004 var dh = Roo.DomHelper;
46005 /** This region's container element
46006 * @type Roo.Element */
46007 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
46008 /** This region's title element
46009 * @type Roo.Element */
46011 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
46012 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
46013 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
46015 this.titleEl.enableDisplayMode();
46016 /** This region's title text element
46017 * @type HTMLElement */
46018 this.titleTextEl = this.titleEl.dom.firstChild;
46019 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
46020 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
46021 this.closeBtn.enableDisplayMode();
46022 this.closeBtn.on("click", this.closeClicked, this);
46023 this.closeBtn.hide();
46025 this.createBody(config);
46026 this.visible = true;
46027 this.collapsed = false;
46029 if(config.hideWhenEmpty){
46031 this.on("paneladded", this.validateVisibility, this);
46032 this.on("panelremoved", this.validateVisibility, this);
46034 this.applyConfig(config);
46037 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
46039 createBody : function(){
46040 /** This region's body element
46041 * @type Roo.Element */
46042 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
46045 applyConfig : function(c){
46046 if(c.collapsible && this.position != "center" && !this.collapsedEl){
46047 var dh = Roo.DomHelper;
46048 if(c.titlebar !== false){
46049 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
46050 this.collapseBtn.on("click", this.collapse, this);
46051 this.collapseBtn.enableDisplayMode();
46053 if(c.showPin === true || this.showPin){
46054 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
46055 this.stickBtn.enableDisplayMode();
46056 this.stickBtn.on("click", this.expand, this);
46057 this.stickBtn.hide();
46060 /** This region's collapsed element
46061 * @type Roo.Element */
46062 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
46063 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
46065 if(c.floatable !== false){
46066 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
46067 this.collapsedEl.on("click", this.collapseClick, this);
46070 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
46071 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
46072 id: "message", unselectable: "on", style:{"float":"left"}});
46073 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
46075 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
46076 this.expandBtn.on("click", this.expand, this);
46078 if(this.collapseBtn){
46079 this.collapseBtn.setVisible(c.collapsible == true);
46081 this.cmargins = c.cmargins || this.cmargins ||
46082 (this.position == "west" || this.position == "east" ?
46083 {top: 0, left: 2, right:2, bottom: 0} :
46084 {top: 2, left: 0, right:0, bottom: 2});
46085 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
46086 this.bottomTabs = c.tabPosition != "top";
46087 this.autoScroll = c.autoScroll || false;
46088 if(this.autoScroll){
46089 this.bodyEl.setStyle("overflow", "auto");
46091 this.bodyEl.setStyle("overflow", "hidden");
46093 //if(c.titlebar !== false){
46094 if((!c.titlebar && !c.title) || c.titlebar === false){
46095 this.titleEl.hide();
46097 this.titleEl.show();
46099 this.titleTextEl.innerHTML = c.title;
46103 this.duration = c.duration || .30;
46104 this.slideDuration = c.slideDuration || .45;
46107 this.collapse(true);
46114 * Returns true if this region is currently visible.
46115 * @return {Boolean}
46117 isVisible : function(){
46118 return this.visible;
46122 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
46123 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
46125 setCollapsedTitle : function(title){
46126 title = title || " ";
46127 if(this.collapsedTitleTextEl){
46128 this.collapsedTitleTextEl.innerHTML = title;
46132 getBox : function(){
46134 if(!this.collapsed){
46135 b = this.el.getBox(false, true);
46137 b = this.collapsedEl.getBox(false, true);
46142 getMargins : function(){
46143 return this.collapsed ? this.cmargins : this.margins;
46146 highlight : function(){
46147 this.el.addClass("x-layout-panel-dragover");
46150 unhighlight : function(){
46151 this.el.removeClass("x-layout-panel-dragover");
46154 updateBox : function(box){
46156 if(!this.collapsed){
46157 this.el.dom.style.left = box.x + "px";
46158 this.el.dom.style.top = box.y + "px";
46159 this.updateBody(box.width, box.height);
46161 this.collapsedEl.dom.style.left = box.x + "px";
46162 this.collapsedEl.dom.style.top = box.y + "px";
46163 this.collapsedEl.setSize(box.width, box.height);
46166 this.tabs.autoSizeTabs();
46170 updateBody : function(w, h){
46172 this.el.setWidth(w);
46173 w -= this.el.getBorderWidth("rl");
46174 if(this.config.adjustments){
46175 w += this.config.adjustments[0];
46179 this.el.setHeight(h);
46180 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
46181 h -= this.el.getBorderWidth("tb");
46182 if(this.config.adjustments){
46183 h += this.config.adjustments[1];
46185 this.bodyEl.setHeight(h);
46187 h = this.tabs.syncHeight(h);
46190 if(this.panelSize){
46191 w = w !== null ? w : this.panelSize.width;
46192 h = h !== null ? h : this.panelSize.height;
46194 if(this.activePanel){
46195 var el = this.activePanel.getEl();
46196 w = w !== null ? w : el.getWidth();
46197 h = h !== null ? h : el.getHeight();
46198 this.panelSize = {width: w, height: h};
46199 this.activePanel.setSize(w, h);
46201 if(Roo.isIE && this.tabs){
46202 this.tabs.el.repaint();
46207 * Returns the container element for this region.
46208 * @return {Roo.Element}
46210 getEl : function(){
46215 * Hides this region.
46218 if(!this.collapsed){
46219 this.el.dom.style.left = "-2000px";
46222 this.collapsedEl.dom.style.left = "-2000px";
46223 this.collapsedEl.hide();
46225 this.visible = false;
46226 this.fireEvent("visibilitychange", this, false);
46230 * Shows this region if it was previously hidden.
46233 if(!this.collapsed){
46236 this.collapsedEl.show();
46238 this.visible = true;
46239 this.fireEvent("visibilitychange", this, true);
46242 closeClicked : function(){
46243 if(this.activePanel){
46244 this.remove(this.activePanel);
46248 collapseClick : function(e){
46250 e.stopPropagation();
46253 e.stopPropagation();
46259 * Collapses this region.
46260 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
46262 collapse : function(skipAnim){
46263 if(this.collapsed) return;
46264 this.collapsed = true;
46266 this.split.el.hide();
46268 if(this.config.animate && skipAnim !== true){
46269 this.fireEvent("invalidated", this);
46270 this.animateCollapse();
46272 this.el.setLocation(-20000,-20000);
46274 this.collapsedEl.show();
46275 this.fireEvent("collapsed", this);
46276 this.fireEvent("invalidated", this);
46280 animateCollapse : function(){
46285 * Expands this region if it was previously collapsed.
46286 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
46287 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
46289 expand : function(e, skipAnim){
46290 if(e) e.stopPropagation();
46291 if(!this.collapsed || this.el.hasActiveFx()) return;
46293 this.afterSlideIn();
46296 this.collapsed = false;
46297 if(this.config.animate && skipAnim !== true){
46298 this.animateExpand();
46302 this.split.el.show();
46304 this.collapsedEl.setLocation(-2000,-2000);
46305 this.collapsedEl.hide();
46306 this.fireEvent("invalidated", this);
46307 this.fireEvent("expanded", this);
46311 animateExpand : function(){
46315 initTabs : function()
46317 this.bodyEl.setStyle("overflow", "hidden");
46318 var ts = new Roo.TabPanel(
46321 tabPosition: this.bottomTabs ? 'bottom' : 'top',
46322 disableTooltips: this.config.disableTabTips,
46323 toolbar : this.config.toolbar
46326 if(this.config.hideTabs){
46327 ts.stripWrap.setDisplayed(false);
46330 ts.resizeTabs = this.config.resizeTabs === true;
46331 ts.minTabWidth = this.config.minTabWidth || 40;
46332 ts.maxTabWidth = this.config.maxTabWidth || 250;
46333 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
46334 ts.monitorResize = false;
46335 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
46336 ts.bodyEl.addClass('x-layout-tabs-body');
46337 this.panels.each(this.initPanelAsTab, this);
46340 initPanelAsTab : function(panel){
46341 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
46342 this.config.closeOnTab && panel.isClosable());
46343 if(panel.tabTip !== undefined){
46344 ti.setTooltip(panel.tabTip);
46346 ti.on("activate", function(){
46347 this.setActivePanel(panel);
46349 if(this.config.closeOnTab){
46350 ti.on("beforeclose", function(t, e){
46352 this.remove(panel);
46358 updatePanelTitle : function(panel, title){
46359 if(this.activePanel == panel){
46360 this.updateTitle(title);
46363 var ti = this.tabs.getTab(panel.getEl().id);
46365 if(panel.tabTip !== undefined){
46366 ti.setTooltip(panel.tabTip);
46371 updateTitle : function(title){
46372 if(this.titleTextEl && !this.config.title){
46373 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
46377 setActivePanel : function(panel){
46378 panel = this.getPanel(panel);
46379 if(this.activePanel && this.activePanel != panel){
46380 this.activePanel.setActiveState(false);
46382 this.activePanel = panel;
46383 panel.setActiveState(true);
46384 if(this.panelSize){
46385 panel.setSize(this.panelSize.width, this.panelSize.height);
46388 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
46390 this.updateTitle(panel.getTitle());
46392 this.fireEvent("invalidated", this);
46394 this.fireEvent("panelactivated", this, panel);
46398 * Shows the specified panel.
46399 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
46400 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
46402 showPanel : function(panel){
46403 if(panel = this.getPanel(panel)){
46405 var tab = this.tabs.getTab(panel.getEl().id);
46406 if(tab.isHidden()){
46407 this.tabs.unhideTab(tab.id);
46411 this.setActivePanel(panel);
46418 * Get the active panel for this region.
46419 * @return {Roo.ContentPanel} The active panel or null
46421 getActivePanel : function(){
46422 return this.activePanel;
46425 validateVisibility : function(){
46426 if(this.panels.getCount() < 1){
46427 this.updateTitle(" ");
46428 this.closeBtn.hide();
46431 if(!this.isVisible()){
46438 * Adds the passed ContentPanel(s) to this region.
46439 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
46440 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
46442 add : function(panel){
46443 if(arguments.length > 1){
46444 for(var i = 0, len = arguments.length; i < len; i++) {
46445 this.add(arguments[i]);
46449 if(this.hasPanel(panel)){
46450 this.showPanel(panel);
46453 panel.setRegion(this);
46454 this.panels.add(panel);
46455 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
46456 this.bodyEl.dom.appendChild(panel.getEl().dom);
46457 if(panel.background !== true){
46458 this.setActivePanel(panel);
46460 this.fireEvent("paneladded", this, panel);
46466 this.initPanelAsTab(panel);
46468 if(panel.background !== true){
46469 this.tabs.activate(panel.getEl().id);
46471 this.fireEvent("paneladded", this, panel);
46476 * Hides the tab for the specified panel.
46477 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46479 hidePanel : function(panel){
46480 if(this.tabs && (panel = this.getPanel(panel))){
46481 this.tabs.hideTab(panel.getEl().id);
46486 * Unhides the tab for a previously hidden panel.
46487 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46489 unhidePanel : function(panel){
46490 if(this.tabs && (panel = this.getPanel(panel))){
46491 this.tabs.unhideTab(panel.getEl().id);
46495 clearPanels : function(){
46496 while(this.panels.getCount() > 0){
46497 this.remove(this.panels.first());
46502 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
46503 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46504 * @param {Boolean} preservePanel Overrides the config preservePanel option
46505 * @return {Roo.ContentPanel} The panel that was removed
46507 remove : function(panel, preservePanel){
46508 panel = this.getPanel(panel);
46513 this.fireEvent("beforeremove", this, panel, e);
46514 if(e.cancel === true){
46517 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
46518 var panelId = panel.getId();
46519 this.panels.removeKey(panelId);
46521 document.body.appendChild(panel.getEl().dom);
46524 this.tabs.removeTab(panel.getEl().id);
46525 }else if (!preservePanel){
46526 this.bodyEl.dom.removeChild(panel.getEl().dom);
46528 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
46529 var p = this.panels.first();
46530 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
46531 tempEl.appendChild(p.getEl().dom);
46532 this.bodyEl.update("");
46533 this.bodyEl.dom.appendChild(p.getEl().dom);
46535 this.updateTitle(p.getTitle());
46537 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
46538 this.setActivePanel(p);
46540 panel.setRegion(null);
46541 if(this.activePanel == panel){
46542 this.activePanel = null;
46544 if(this.config.autoDestroy !== false && preservePanel !== true){
46545 try{panel.destroy();}catch(e){}
46547 this.fireEvent("panelremoved", this, panel);
46552 * Returns the TabPanel component used by this region
46553 * @return {Roo.TabPanel}
46555 getTabs : function(){
46559 createTool : function(parentEl, className){
46560 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
46561 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
46562 btn.addClassOnOver("x-layout-tools-button-over");
46567 * Ext JS Library 1.1.1
46568 * Copyright(c) 2006-2007, Ext JS, LLC.
46570 * Originally Released Under LGPL - original licence link has changed is not relivant.
46573 * <script type="text/javascript">
46579 * @class Roo.SplitLayoutRegion
46580 * @extends Roo.LayoutRegion
46581 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
46583 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
46584 this.cursor = cursor;
46585 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
46588 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
46589 splitTip : "Drag to resize.",
46590 collapsibleSplitTip : "Drag to resize. Double click to hide.",
46591 useSplitTips : false,
46593 applyConfig : function(config){
46594 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
46597 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
46598 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
46599 /** The SplitBar for this region
46600 * @type Roo.SplitBar */
46601 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
46602 this.split.on("moved", this.onSplitMove, this);
46603 this.split.useShim = config.useShim === true;
46604 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
46605 if(this.useSplitTips){
46606 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
46608 if(config.collapsible){
46609 this.split.el.on("dblclick", this.collapse, this);
46612 if(typeof config.minSize != "undefined"){
46613 this.split.minSize = config.minSize;
46615 if(typeof config.maxSize != "undefined"){
46616 this.split.maxSize = config.maxSize;
46618 if(config.hideWhenEmpty || config.hidden || config.collapsed){
46619 this.hideSplitter();
46624 getHMaxSize : function(){
46625 var cmax = this.config.maxSize || 10000;
46626 var center = this.mgr.getRegion("center");
46627 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
46630 getVMaxSize : function(){
46631 var cmax = this.config.maxSize || 10000;
46632 var center = this.mgr.getRegion("center");
46633 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
46636 onSplitMove : function(split, newSize){
46637 this.fireEvent("resized", this, newSize);
46641 * Returns the {@link Roo.SplitBar} for this region.
46642 * @return {Roo.SplitBar}
46644 getSplitBar : function(){
46649 this.hideSplitter();
46650 Roo.SplitLayoutRegion.superclass.hide.call(this);
46653 hideSplitter : function(){
46655 this.split.el.setLocation(-2000,-2000);
46656 this.split.el.hide();
46662 this.split.el.show();
46664 Roo.SplitLayoutRegion.superclass.show.call(this);
46667 beforeSlide: function(){
46668 if(Roo.isGecko){// firefox overflow auto bug workaround
46669 this.bodyEl.clip();
46670 if(this.tabs) this.tabs.bodyEl.clip();
46671 if(this.activePanel){
46672 this.activePanel.getEl().clip();
46674 if(this.activePanel.beforeSlide){
46675 this.activePanel.beforeSlide();
46681 afterSlide : function(){
46682 if(Roo.isGecko){// firefox overflow auto bug workaround
46683 this.bodyEl.unclip();
46684 if(this.tabs) this.tabs.bodyEl.unclip();
46685 if(this.activePanel){
46686 this.activePanel.getEl().unclip();
46687 if(this.activePanel.afterSlide){
46688 this.activePanel.afterSlide();
46694 initAutoHide : function(){
46695 if(this.autoHide !== false){
46696 if(!this.autoHideHd){
46697 var st = new Roo.util.DelayedTask(this.slideIn, this);
46698 this.autoHideHd = {
46699 "mouseout": function(e){
46700 if(!e.within(this.el, true)){
46704 "mouseover" : function(e){
46710 this.el.on(this.autoHideHd);
46714 clearAutoHide : function(){
46715 if(this.autoHide !== false){
46716 this.el.un("mouseout", this.autoHideHd.mouseout);
46717 this.el.un("mouseover", this.autoHideHd.mouseover);
46721 clearMonitor : function(){
46722 Roo.get(document).un("click", this.slideInIf, this);
46725 // these names are backwards but not changed for compat
46726 slideOut : function(){
46727 if(this.isSlid || this.el.hasActiveFx()){
46730 this.isSlid = true;
46731 if(this.collapseBtn){
46732 this.collapseBtn.hide();
46734 this.closeBtnState = this.closeBtn.getStyle('display');
46735 this.closeBtn.hide();
46737 this.stickBtn.show();
46740 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
46741 this.beforeSlide();
46742 this.el.setStyle("z-index", 10001);
46743 this.el.slideIn(this.getSlideAnchor(), {
46744 callback: function(){
46746 this.initAutoHide();
46747 Roo.get(document).on("click", this.slideInIf, this);
46748 this.fireEvent("slideshow", this);
46755 afterSlideIn : function(){
46756 this.clearAutoHide();
46757 this.isSlid = false;
46758 this.clearMonitor();
46759 this.el.setStyle("z-index", "");
46760 if(this.collapseBtn){
46761 this.collapseBtn.show();
46763 this.closeBtn.setStyle('display', this.closeBtnState);
46765 this.stickBtn.hide();
46767 this.fireEvent("slidehide", this);
46770 slideIn : function(cb){
46771 if(!this.isSlid || this.el.hasActiveFx()){
46775 this.isSlid = false;
46776 this.beforeSlide();
46777 this.el.slideOut(this.getSlideAnchor(), {
46778 callback: function(){
46779 this.el.setLeftTop(-10000, -10000);
46781 this.afterSlideIn();
46789 slideInIf : function(e){
46790 if(!e.within(this.el)){
46795 animateCollapse : function(){
46796 this.beforeSlide();
46797 this.el.setStyle("z-index", 20000);
46798 var anchor = this.getSlideAnchor();
46799 this.el.slideOut(anchor, {
46800 callback : function(){
46801 this.el.setStyle("z-index", "");
46802 this.collapsedEl.slideIn(anchor, {duration:.3});
46804 this.el.setLocation(-10000,-10000);
46806 this.fireEvent("collapsed", this);
46813 animateExpand : function(){
46814 this.beforeSlide();
46815 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
46816 this.el.setStyle("z-index", 20000);
46817 this.collapsedEl.hide({
46820 this.el.slideIn(this.getSlideAnchor(), {
46821 callback : function(){
46822 this.el.setStyle("z-index", "");
46825 this.split.el.show();
46827 this.fireEvent("invalidated", this);
46828 this.fireEvent("expanded", this);
46856 getAnchor : function(){
46857 return this.anchors[this.position];
46860 getCollapseAnchor : function(){
46861 return this.canchors[this.position];
46864 getSlideAnchor : function(){
46865 return this.sanchors[this.position];
46868 getAlignAdj : function(){
46869 var cm = this.cmargins;
46870 switch(this.position){
46886 getExpandAdj : function(){
46887 var c = this.collapsedEl, cm = this.cmargins;
46888 switch(this.position){
46890 return [-(cm.right+c.getWidth()+cm.left), 0];
46893 return [cm.right+c.getWidth()+cm.left, 0];
46896 return [0, -(cm.top+cm.bottom+c.getHeight())];
46899 return [0, cm.top+cm.bottom+c.getHeight()];
46905 * Ext JS Library 1.1.1
46906 * Copyright(c) 2006-2007, Ext JS, LLC.
46908 * Originally Released Under LGPL - original licence link has changed is not relivant.
46911 * <script type="text/javascript">
46914 * These classes are private internal classes
46916 Roo.CenterLayoutRegion = function(mgr, config){
46917 Roo.LayoutRegion.call(this, mgr, config, "center");
46918 this.visible = true;
46919 this.minWidth = config.minWidth || 20;
46920 this.minHeight = config.minHeight || 20;
46923 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
46925 // center panel can't be hidden
46929 // center panel can't be hidden
46932 getMinWidth: function(){
46933 return this.minWidth;
46936 getMinHeight: function(){
46937 return this.minHeight;
46942 Roo.NorthLayoutRegion = function(mgr, config){
46943 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
46945 this.split.placement = Roo.SplitBar.TOP;
46946 this.split.orientation = Roo.SplitBar.VERTICAL;
46947 this.split.el.addClass("x-layout-split-v");
46949 var size = config.initialSize || config.height;
46950 if(typeof size != "undefined"){
46951 this.el.setHeight(size);
46954 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
46955 orientation: Roo.SplitBar.VERTICAL,
46956 getBox : function(){
46957 if(this.collapsed){
46958 return this.collapsedEl.getBox();
46960 var box = this.el.getBox();
46962 box.height += this.split.el.getHeight();
46967 updateBox : function(box){
46968 if(this.split && !this.collapsed){
46969 box.height -= this.split.el.getHeight();
46970 this.split.el.setLeft(box.x);
46971 this.split.el.setTop(box.y+box.height);
46972 this.split.el.setWidth(box.width);
46974 if(this.collapsed){
46975 this.updateBody(box.width, null);
46977 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46981 Roo.SouthLayoutRegion = function(mgr, config){
46982 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
46984 this.split.placement = Roo.SplitBar.BOTTOM;
46985 this.split.orientation = Roo.SplitBar.VERTICAL;
46986 this.split.el.addClass("x-layout-split-v");
46988 var size = config.initialSize || config.height;
46989 if(typeof size != "undefined"){
46990 this.el.setHeight(size);
46993 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
46994 orientation: Roo.SplitBar.VERTICAL,
46995 getBox : function(){
46996 if(this.collapsed){
46997 return this.collapsedEl.getBox();
46999 var box = this.el.getBox();
47001 var sh = this.split.el.getHeight();
47008 updateBox : function(box){
47009 if(this.split && !this.collapsed){
47010 var sh = this.split.el.getHeight();
47013 this.split.el.setLeft(box.x);
47014 this.split.el.setTop(box.y-sh);
47015 this.split.el.setWidth(box.width);
47017 if(this.collapsed){
47018 this.updateBody(box.width, null);
47020 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47024 Roo.EastLayoutRegion = function(mgr, config){
47025 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
47027 this.split.placement = Roo.SplitBar.RIGHT;
47028 this.split.orientation = Roo.SplitBar.HORIZONTAL;
47029 this.split.el.addClass("x-layout-split-h");
47031 var size = config.initialSize || config.width;
47032 if(typeof size != "undefined"){
47033 this.el.setWidth(size);
47036 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
47037 orientation: Roo.SplitBar.HORIZONTAL,
47038 getBox : function(){
47039 if(this.collapsed){
47040 return this.collapsedEl.getBox();
47042 var box = this.el.getBox();
47044 var sw = this.split.el.getWidth();
47051 updateBox : function(box){
47052 if(this.split && !this.collapsed){
47053 var sw = this.split.el.getWidth();
47055 this.split.el.setLeft(box.x);
47056 this.split.el.setTop(box.y);
47057 this.split.el.setHeight(box.height);
47060 if(this.collapsed){
47061 this.updateBody(null, box.height);
47063 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47067 Roo.WestLayoutRegion = function(mgr, config){
47068 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
47070 this.split.placement = Roo.SplitBar.LEFT;
47071 this.split.orientation = Roo.SplitBar.HORIZONTAL;
47072 this.split.el.addClass("x-layout-split-h");
47074 var size = config.initialSize || config.width;
47075 if(typeof size != "undefined"){
47076 this.el.setWidth(size);
47079 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
47080 orientation: Roo.SplitBar.HORIZONTAL,
47081 getBox : function(){
47082 if(this.collapsed){
47083 return this.collapsedEl.getBox();
47085 var box = this.el.getBox();
47087 box.width += this.split.el.getWidth();
47092 updateBox : function(box){
47093 if(this.split && !this.collapsed){
47094 var sw = this.split.el.getWidth();
47096 this.split.el.setLeft(box.x+box.width);
47097 this.split.el.setTop(box.y);
47098 this.split.el.setHeight(box.height);
47100 if(this.collapsed){
47101 this.updateBody(null, box.height);
47103 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47108 * Ext JS Library 1.1.1
47109 * Copyright(c) 2006-2007, Ext JS, LLC.
47111 * Originally Released Under LGPL - original licence link has changed is not relivant.
47114 * <script type="text/javascript">
47119 * Private internal class for reading and applying state
47121 Roo.LayoutStateManager = function(layout){
47122 // default empty state
47131 Roo.LayoutStateManager.prototype = {
47132 init : function(layout, provider){
47133 this.provider = provider;
47134 var state = provider.get(layout.id+"-layout-state");
47136 var wasUpdating = layout.isUpdating();
47138 layout.beginUpdate();
47140 for(var key in state){
47141 if(typeof state[key] != "function"){
47142 var rstate = state[key];
47143 var r = layout.getRegion(key);
47146 r.resizeTo(rstate.size);
47148 if(rstate.collapsed == true){
47151 r.expand(null, true);
47157 layout.endUpdate();
47159 this.state = state;
47161 this.layout = layout;
47162 layout.on("regionresized", this.onRegionResized, this);
47163 layout.on("regioncollapsed", this.onRegionCollapsed, this);
47164 layout.on("regionexpanded", this.onRegionExpanded, this);
47167 storeState : function(){
47168 this.provider.set(this.layout.id+"-layout-state", this.state);
47171 onRegionResized : function(region, newSize){
47172 this.state[region.getPosition()].size = newSize;
47176 onRegionCollapsed : function(region){
47177 this.state[region.getPosition()].collapsed = true;
47181 onRegionExpanded : function(region){
47182 this.state[region.getPosition()].collapsed = false;
47187 * Ext JS Library 1.1.1
47188 * Copyright(c) 2006-2007, Ext JS, LLC.
47190 * Originally Released Under LGPL - original licence link has changed is not relivant.
47193 * <script type="text/javascript">
47196 * @class Roo.ContentPanel
47197 * @extends Roo.util.Observable
47198 * A basic ContentPanel element.
47199 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
47200 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
47201 * @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
47202 * @cfg {Boolean} closable True if the panel can be closed/removed
47203 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
47204 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
47205 * @cfg {Toolbar} toolbar A toolbar for this panel
47206 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
47207 * @cfg {String} title The title for this panel
47208 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
47209 * @cfg {String} url Calls {@link #setUrl} with this value
47210 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
47211 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
47212 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
47213 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
47216 * Create a new ContentPanel.
47217 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
47218 * @param {String/Object} config A string to set only the title or a config object
47219 * @param {String} content (optional) Set the HTML content for this panel
47220 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
47222 Roo.ContentPanel = function(el, config, content){
47226 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
47230 if (config && config.parentLayout) {
47231 el = config.parentLayout.el.createChild();
47234 if(el.autoCreate){ // xtype is available if this is called from factory
47238 this.el = Roo.get(el);
47239 if(!this.el && config && config.autoCreate){
47240 if(typeof config.autoCreate == "object"){
47241 if(!config.autoCreate.id){
47242 config.autoCreate.id = config.id||el;
47244 this.el = Roo.DomHelper.append(document.body,
47245 config.autoCreate, true);
47247 this.el = Roo.DomHelper.append(document.body,
47248 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
47251 this.closable = false;
47252 this.loaded = false;
47253 this.active = false;
47254 if(typeof config == "string"){
47255 this.title = config;
47257 Roo.apply(this, config);
47260 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
47261 this.wrapEl = this.el.wrap();
47262 this.toolbar.container = this.el.insertSibling(false, 'before');
47263 this.toolbar = new Roo.Toolbar(this.toolbar);
47269 this.resizeEl = Roo.get(this.resizeEl, true);
47271 this.resizeEl = this.el;
47276 * Fires when this panel is activated.
47277 * @param {Roo.ContentPanel} this
47281 * @event deactivate
47282 * Fires when this panel is activated.
47283 * @param {Roo.ContentPanel} this
47285 "deactivate" : true,
47289 * Fires when this panel is resized if fitToFrame is true.
47290 * @param {Roo.ContentPanel} this
47291 * @param {Number} width The width after any component adjustments
47292 * @param {Number} height The height after any component adjustments
47298 * Fires when this tab is created
47299 * @param {Roo.ContentPanel} this
47306 if(this.autoScroll){
47307 this.resizeEl.setStyle("overflow", "auto");
47309 // fix randome scrolling
47310 this.el.on('scroll', function() {
47311 Roo.log('fix random scolling');
47312 this.scrollTo('top',0);
47315 content = content || this.content;
47317 this.setContent(content);
47319 if(config && config.url){
47320 this.setUrl(this.url, this.params, this.loadOnce);
47325 Roo.ContentPanel.superclass.constructor.call(this);
47327 this.fireEvent('render', this);
47330 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
47332 setRegion : function(region){
47333 this.region = region;
47335 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
47337 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
47342 * Returns the toolbar for this Panel if one was configured.
47343 * @return {Roo.Toolbar}
47345 getToolbar : function(){
47346 return this.toolbar;
47349 setActiveState : function(active){
47350 this.active = active;
47352 this.fireEvent("deactivate", this);
47354 this.fireEvent("activate", this);
47358 * Updates this panel's element
47359 * @param {String} content The new content
47360 * @param {Boolean} loadScripts (optional) true to look for and process scripts
47362 setContent : function(content, loadScripts){
47363 this.el.update(content, loadScripts);
47366 ignoreResize : function(w, h){
47367 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
47370 this.lastSize = {width: w, height: h};
47375 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
47376 * @return {Roo.UpdateManager} The UpdateManager
47378 getUpdateManager : function(){
47379 return this.el.getUpdateManager();
47382 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
47383 * @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:
47386 url: "your-url.php",
47387 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
47388 callback: yourFunction,
47389 scope: yourObject, //(optional scope)
47392 text: "Loading...",
47397 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
47398 * 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.
47399 * @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}
47400 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
47401 * @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.
47402 * @return {Roo.ContentPanel} this
47405 var um = this.el.getUpdateManager();
47406 um.update.apply(um, arguments);
47412 * 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.
47413 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
47414 * @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)
47415 * @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)
47416 * @return {Roo.UpdateManager} The UpdateManager
47418 setUrl : function(url, params, loadOnce){
47419 if(this.refreshDelegate){
47420 this.removeListener("activate", this.refreshDelegate);
47422 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
47423 this.on("activate", this.refreshDelegate);
47424 return this.el.getUpdateManager();
47427 _handleRefresh : function(url, params, loadOnce){
47428 if(!loadOnce || !this.loaded){
47429 var updater = this.el.getUpdateManager();
47430 updater.update(url, params, this._setLoaded.createDelegate(this));
47434 _setLoaded : function(){
47435 this.loaded = true;
47439 * Returns this panel's id
47442 getId : function(){
47447 * Returns this panel's element - used by regiosn to add.
47448 * @return {Roo.Element}
47450 getEl : function(){
47451 return this.wrapEl || this.el;
47454 adjustForComponents : function(width, height){
47455 if(this.resizeEl != this.el){
47456 width -= this.el.getFrameWidth('lr');
47457 height -= this.el.getFrameWidth('tb');
47460 var te = this.toolbar.getEl();
47461 height -= te.getHeight();
47462 te.setWidth(width);
47464 if(this.adjustments){
47465 width += this.adjustments[0];
47466 height += this.adjustments[1];
47468 return {"width": width, "height": height};
47471 setSize : function(width, height){
47472 if(this.fitToFrame && !this.ignoreResize(width, height)){
47473 if(this.fitContainer && this.resizeEl != this.el){
47474 this.el.setSize(width, height);
47476 var size = this.adjustForComponents(width, height);
47477 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
47478 this.fireEvent('resize', this, size.width, size.height);
47483 * Returns this panel's title
47486 getTitle : function(){
47491 * Set this panel's title
47492 * @param {String} title
47494 setTitle : function(title){
47495 this.title = title;
47497 this.region.updatePanelTitle(this, title);
47502 * Returns true is this panel was configured to be closable
47503 * @return {Boolean}
47505 isClosable : function(){
47506 return this.closable;
47509 beforeSlide : function(){
47511 this.resizeEl.clip();
47514 afterSlide : function(){
47516 this.resizeEl.unclip();
47520 * Force a content refresh from the URL specified in the {@link #setUrl} method.
47521 * Will fail silently if the {@link #setUrl} method has not been called.
47522 * This does not activate the panel, just updates its content.
47524 refresh : function(){
47525 if(this.refreshDelegate){
47526 this.loaded = false;
47527 this.refreshDelegate();
47532 * Destroys this panel
47534 destroy : function(){
47535 this.el.removeAllListeners();
47536 var tempEl = document.createElement("span");
47537 tempEl.appendChild(this.el.dom);
47538 tempEl.innerHTML = "";
47544 * form - if the content panel contains a form - this is a reference to it.
47545 * @type {Roo.form.Form}
47549 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
47550 * This contains a reference to it.
47556 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
47566 * @param {Object} cfg Xtype definition of item to add.
47569 addxtype : function(cfg) {
47571 if (cfg.xtype.match(/^Form$/)) {
47572 var el = this.el.createChild();
47574 this.form = new Roo.form.Form(cfg);
47577 if ( this.form.allItems.length) this.form.render(el.dom);
47580 // should only have one of theses..
47581 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
47583 cfg.el = this.el.appendChild(document.createElement("div"));
47586 var ret = new Roo.factory(cfg);
47587 ret.render && ret.render(false, ''); // render blank..
47596 * @class Roo.GridPanel
47597 * @extends Roo.ContentPanel
47599 * Create a new GridPanel.
47600 * @param {Roo.grid.Grid} grid The grid for this panel
47601 * @param {String/Object} config A string to set only the panel's title, or a config object
47603 Roo.GridPanel = function(grid, config){
47606 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
47607 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
47609 this.wrapper.dom.appendChild(grid.getGridEl().dom);
47611 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
47614 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
47616 // xtype created footer. - not sure if will work as we normally have to render first..
47617 if (this.footer && !this.footer.el && this.footer.xtype) {
47619 this.footer.container = this.grid.getView().getFooterPanel(true);
47620 this.footer.dataSource = this.grid.dataSource;
47621 this.footer = Roo.factory(this.footer, Roo);
47625 grid.monitorWindowResize = false; // turn off autosizing
47626 grid.autoHeight = false;
47627 grid.autoWidth = false;
47629 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
47632 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
47633 getId : function(){
47634 return this.grid.id;
47638 * Returns the grid for this panel
47639 * @return {Roo.grid.Grid}
47641 getGrid : function(){
47645 setSize : function(width, height){
47646 if(!this.ignoreResize(width, height)){
47647 var grid = this.grid;
47648 var size = this.adjustForComponents(width, height);
47649 grid.getGridEl().setSize(size.width, size.height);
47654 beforeSlide : function(){
47655 this.grid.getView().scroller.clip();
47658 afterSlide : function(){
47659 this.grid.getView().scroller.unclip();
47662 destroy : function(){
47663 this.grid.destroy();
47665 Roo.GridPanel.superclass.destroy.call(this);
47671 * @class Roo.NestedLayoutPanel
47672 * @extends Roo.ContentPanel
47674 * Create a new NestedLayoutPanel.
47677 * @param {Roo.BorderLayout} layout The layout for this panel
47678 * @param {String/Object} config A string to set only the title or a config object
47680 Roo.NestedLayoutPanel = function(layout, config)
47682 // construct with only one argument..
47683 /* FIXME - implement nicer consturctors
47684 if (layout.layout) {
47686 layout = config.layout;
47687 delete config.layout;
47689 if (layout.xtype && !layout.getEl) {
47690 // then layout needs constructing..
47691 layout = Roo.factory(layout, Roo);
47696 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
47698 layout.monitorWindowResize = false; // turn off autosizing
47699 this.layout = layout;
47700 this.layout.getEl().addClass("x-layout-nested-layout");
47707 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
47709 setSize : function(width, height){
47710 if(!this.ignoreResize(width, height)){
47711 var size = this.adjustForComponents(width, height);
47712 var el = this.layout.getEl();
47713 el.setSize(size.width, size.height);
47714 var touch = el.dom.offsetWidth;
47715 this.layout.layout();
47716 // ie requires a double layout on the first pass
47717 if(Roo.isIE && !this.initialized){
47718 this.initialized = true;
47719 this.layout.layout();
47724 // activate all subpanels if not currently active..
47726 setActiveState : function(active){
47727 this.active = active;
47729 this.fireEvent("deactivate", this);
47733 this.fireEvent("activate", this);
47734 // not sure if this should happen before or after..
47735 if (!this.layout) {
47736 return; // should not happen..
47739 for (var r in this.layout.regions) {
47740 reg = this.layout.getRegion(r);
47741 if (reg.getActivePanel()) {
47742 //reg.showPanel(reg.getActivePanel()); // force it to activate..
47743 reg.setActivePanel(reg.getActivePanel());
47746 if (!reg.panels.length) {
47749 reg.showPanel(reg.getPanel(0));
47758 * Returns the nested BorderLayout for this panel
47759 * @return {Roo.BorderLayout}
47761 getLayout : function(){
47762 return this.layout;
47766 * Adds a xtype elements to the layout of the nested panel
47770 xtype : 'ContentPanel',
47777 xtype : 'NestedLayoutPanel',
47783 items : [ ... list of content panels or nested layout panels.. ]
47787 * @param {Object} cfg Xtype definition of item to add.
47789 addxtype : function(cfg) {
47790 return this.layout.addxtype(cfg);
47795 Roo.ScrollPanel = function(el, config, content){
47796 config = config || {};
47797 config.fitToFrame = true;
47798 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
47800 this.el.dom.style.overflow = "hidden";
47801 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
47802 this.el.removeClass("x-layout-inactive-content");
47803 this.el.on("mousewheel", this.onWheel, this);
47805 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
47806 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
47807 up.unselectable(); down.unselectable();
47808 up.on("click", this.scrollUp, this);
47809 down.on("click", this.scrollDown, this);
47810 up.addClassOnOver("x-scroller-btn-over");
47811 down.addClassOnOver("x-scroller-btn-over");
47812 up.addClassOnClick("x-scroller-btn-click");
47813 down.addClassOnClick("x-scroller-btn-click");
47814 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
47816 this.resizeEl = this.el;
47817 this.el = wrap; this.up = up; this.down = down;
47820 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
47822 wheelIncrement : 5,
47823 scrollUp : function(){
47824 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
47827 scrollDown : function(){
47828 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
47831 afterScroll : function(){
47832 var el = this.resizeEl;
47833 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
47834 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47835 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47838 setSize : function(){
47839 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
47840 this.afterScroll();
47843 onWheel : function(e){
47844 var d = e.getWheelDelta();
47845 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
47846 this.afterScroll();
47850 setContent : function(content, loadScripts){
47851 this.resizeEl.update(content, loadScripts);
47865 * @class Roo.TreePanel
47866 * @extends Roo.ContentPanel
47868 * Create a new TreePanel. - defaults to fit/scoll contents.
47869 * @param {String/Object} config A string to set only the panel's title, or a config object
47870 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
47872 Roo.TreePanel = function(config){
47873 var el = config.el;
47874 var tree = config.tree;
47875 delete config.tree;
47876 delete config.el; // hopefull!
47878 // wrapper for IE7 strict & safari scroll issue
47880 var treeEl = el.createChild();
47881 config.resizeEl = treeEl;
47885 Roo.TreePanel.superclass.constructor.call(this, el, config);
47888 this.tree = new Roo.tree.TreePanel(treeEl , tree);
47889 //console.log(tree);
47890 this.on('activate', function()
47892 if (this.tree.rendered) {
47895 //console.log('render tree');
47896 this.tree.render();
47899 this.on('resize', function (cp, w, h) {
47900 this.tree.innerCt.setWidth(w);
47901 this.tree.innerCt.setHeight(h);
47902 this.tree.innerCt.setStyle('overflow-y', 'auto');
47909 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
47926 * Ext JS Library 1.1.1
47927 * Copyright(c) 2006-2007, Ext JS, LLC.
47929 * Originally Released Under LGPL - original licence link has changed is not relivant.
47932 * <script type="text/javascript">
47937 * @class Roo.ReaderLayout
47938 * @extends Roo.BorderLayout
47939 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
47940 * center region containing two nested regions (a top one for a list view and one for item preview below),
47941 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
47942 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
47943 * expedites the setup of the overall layout and regions for this common application style.
47946 var reader = new Roo.ReaderLayout();
47947 var CP = Roo.ContentPanel; // shortcut for adding
47949 reader.beginUpdate();
47950 reader.add("north", new CP("north", "North"));
47951 reader.add("west", new CP("west", {title: "West"}));
47952 reader.add("east", new CP("east", {title: "East"}));
47954 reader.regions.listView.add(new CP("listView", "List"));
47955 reader.regions.preview.add(new CP("preview", "Preview"));
47956 reader.endUpdate();
47959 * Create a new ReaderLayout
47960 * @param {Object} config Configuration options
47961 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
47962 * document.body if omitted)
47964 Roo.ReaderLayout = function(config, renderTo){
47965 var c = config || {size:{}};
47966 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
47967 north: c.north !== false ? Roo.apply({
47971 }, c.north) : false,
47972 west: c.west !== false ? Roo.apply({
47980 margins:{left:5,right:0,bottom:5,top:5},
47981 cmargins:{left:5,right:5,bottom:5,top:5}
47982 }, c.west) : false,
47983 east: c.east !== false ? Roo.apply({
47991 margins:{left:0,right:5,bottom:5,top:5},
47992 cmargins:{left:5,right:5,bottom:5,top:5}
47993 }, c.east) : false,
47994 center: Roo.apply({
47995 tabPosition: 'top',
47999 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
48003 this.el.addClass('x-reader');
48005 this.beginUpdate();
48007 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
48008 south: c.preview !== false ? Roo.apply({
48015 cmargins:{top:5,left:0, right:0, bottom:0}
48016 }, c.preview) : false,
48017 center: Roo.apply({
48023 this.add('center', new Roo.NestedLayoutPanel(inner,
48024 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
48028 this.regions.preview = inner.getRegion('south');
48029 this.regions.listView = inner.getRegion('center');
48032 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
48034 * Ext JS Library 1.1.1
48035 * Copyright(c) 2006-2007, Ext JS, LLC.
48037 * Originally Released Under LGPL - original licence link has changed is not relivant.
48040 * <script type="text/javascript">
48044 * @class Roo.grid.Grid
48045 * @extends Roo.util.Observable
48046 * This class represents the primary interface of a component based grid control.
48047 * <br><br>Usage:<pre><code>
48048 var grid = new Roo.grid.Grid("my-container-id", {
48051 selModel: mySelectionModel,
48052 autoSizeColumns: true,
48053 monitorWindowResize: false,
48054 trackMouseOver: true
48059 * <b>Common Problems:</b><br/>
48060 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
48061 * element will correct this<br/>
48062 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
48063 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
48064 * are unpredictable.<br/>
48065 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
48066 * grid to calculate dimensions/offsets.<br/>
48068 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
48069 * The container MUST have some type of size defined for the grid to fill. The container will be
48070 * automatically set to position relative if it isn't already.
48071 * @param {Object} config A config object that sets properties on this grid.
48073 Roo.grid.Grid = function(container, config){
48074 // initialize the container
48075 this.container = Roo.get(container);
48076 this.container.update("");
48077 this.container.setStyle("overflow", "hidden");
48078 this.container.addClass('x-grid-container');
48080 this.id = this.container.id;
48082 Roo.apply(this, config);
48083 // check and correct shorthanded configs
48085 this.dataSource = this.ds;
48089 this.colModel = this.cm;
48093 this.selModel = this.sm;
48097 if (this.selModel) {
48098 this.selModel = Roo.factory(this.selModel, Roo.grid);
48099 this.sm = this.selModel;
48100 this.sm.xmodule = this.xmodule || false;
48102 if (typeof(this.colModel.config) == 'undefined') {
48103 this.colModel = new Roo.grid.ColumnModel(this.colModel);
48104 this.cm = this.colModel;
48105 this.cm.xmodule = this.xmodule || false;
48107 if (this.dataSource) {
48108 this.dataSource= Roo.factory(this.dataSource, Roo.data);
48109 this.ds = this.dataSource;
48110 this.ds.xmodule = this.xmodule || false;
48117 this.container.setWidth(this.width);
48121 this.container.setHeight(this.height);
48128 * The raw click event for the entire grid.
48129 * @param {Roo.EventObject} e
48134 * The raw dblclick event for the entire grid.
48135 * @param {Roo.EventObject} e
48139 * @event contextmenu
48140 * The raw contextmenu event for the entire grid.
48141 * @param {Roo.EventObject} e
48143 "contextmenu" : true,
48146 * The raw mousedown event for the entire grid.
48147 * @param {Roo.EventObject} e
48149 "mousedown" : true,
48152 * The raw mouseup event for the entire grid.
48153 * @param {Roo.EventObject} e
48158 * The raw mouseover event for the entire grid.
48159 * @param {Roo.EventObject} e
48161 "mouseover" : true,
48164 * The raw mouseout event for the entire grid.
48165 * @param {Roo.EventObject} e
48170 * The raw keypress event for the entire grid.
48171 * @param {Roo.EventObject} e
48176 * The raw keydown event for the entire grid.
48177 * @param {Roo.EventObject} e
48185 * Fires when a cell is clicked
48186 * @param {Grid} this
48187 * @param {Number} rowIndex
48188 * @param {Number} columnIndex
48189 * @param {Roo.EventObject} e
48191 "cellclick" : true,
48193 * @event celldblclick
48194 * Fires when a cell is double clicked
48195 * @param {Grid} this
48196 * @param {Number} rowIndex
48197 * @param {Number} columnIndex
48198 * @param {Roo.EventObject} e
48200 "celldblclick" : true,
48203 * Fires when a row is clicked
48204 * @param {Grid} this
48205 * @param {Number} rowIndex
48206 * @param {Roo.EventObject} e
48210 * @event rowdblclick
48211 * Fires when a row is double clicked
48212 * @param {Grid} this
48213 * @param {Number} rowIndex
48214 * @param {Roo.EventObject} e
48216 "rowdblclick" : true,
48218 * @event headerclick
48219 * Fires when a header is clicked
48220 * @param {Grid} this
48221 * @param {Number} columnIndex
48222 * @param {Roo.EventObject} e
48224 "headerclick" : true,
48226 * @event headerdblclick
48227 * Fires when a header cell is double clicked
48228 * @param {Grid} this
48229 * @param {Number} columnIndex
48230 * @param {Roo.EventObject} e
48232 "headerdblclick" : true,
48234 * @event rowcontextmenu
48235 * Fires when a row is right clicked
48236 * @param {Grid} this
48237 * @param {Number} rowIndex
48238 * @param {Roo.EventObject} e
48240 "rowcontextmenu" : true,
48242 * @event cellcontextmenu
48243 * Fires when a cell is right clicked
48244 * @param {Grid} this
48245 * @param {Number} rowIndex
48246 * @param {Number} cellIndex
48247 * @param {Roo.EventObject} e
48249 "cellcontextmenu" : true,
48251 * @event headercontextmenu
48252 * Fires when a header is right clicked
48253 * @param {Grid} this
48254 * @param {Number} columnIndex
48255 * @param {Roo.EventObject} e
48257 "headercontextmenu" : true,
48259 * @event bodyscroll
48260 * Fires when the body element is scrolled
48261 * @param {Number} scrollLeft
48262 * @param {Number} scrollTop
48264 "bodyscroll" : true,
48266 * @event columnresize
48267 * Fires when the user resizes a column
48268 * @param {Number} columnIndex
48269 * @param {Number} newSize
48271 "columnresize" : true,
48273 * @event columnmove
48274 * Fires when the user moves a column
48275 * @param {Number} oldIndex
48276 * @param {Number} newIndex
48278 "columnmove" : true,
48281 * Fires when row(s) start being dragged
48282 * @param {Grid} this
48283 * @param {Roo.GridDD} dd The drag drop object
48284 * @param {event} e The raw browser event
48286 "startdrag" : true,
48289 * Fires when a drag operation is complete
48290 * @param {Grid} this
48291 * @param {Roo.GridDD} dd The drag drop object
48292 * @param {event} e The raw browser event
48297 * Fires when dragged row(s) are dropped on a valid DD target
48298 * @param {Grid} this
48299 * @param {Roo.GridDD} dd The drag drop object
48300 * @param {String} targetId The target drag drop object
48301 * @param {event} e The raw browser event
48306 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
48307 * @param {Grid} this
48308 * @param {Roo.GridDD} dd The drag drop object
48309 * @param {String} targetId The target drag drop object
48310 * @param {event} e The raw browser event
48315 * Fires when the dragged row(s) first cross another DD target while being dragged
48316 * @param {Grid} this
48317 * @param {Roo.GridDD} dd The drag drop object
48318 * @param {String} targetId The target drag drop object
48319 * @param {event} e The raw browser event
48321 "dragenter" : true,
48324 * Fires when the dragged row(s) leave another DD target while being dragged
48325 * @param {Grid} this
48326 * @param {Roo.GridDD} dd The drag drop object
48327 * @param {String} targetId The target drag drop object
48328 * @param {event} e The raw browser event
48333 * Fires when a row is rendered, so you can change add a style to it.
48334 * @param {GridView} gridview The grid view
48335 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
48341 * Fires when the grid is rendered
48342 * @param {Grid} grid
48347 Roo.grid.Grid.superclass.constructor.call(this);
48349 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
48352 * @cfg {String} ddGroup - drag drop group.
48356 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
48358 minColumnWidth : 25,
48361 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
48362 * <b>on initial render.</b> It is more efficient to explicitly size the columns
48363 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
48365 autoSizeColumns : false,
48368 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
48370 autoSizeHeaders : true,
48373 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
48375 monitorWindowResize : true,
48378 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
48379 * rows measured to get a columns size. Default is 0 (all rows).
48381 maxRowsToMeasure : 0,
48384 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
48386 trackMouseOver : true,
48389 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
48393 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
48395 enableDragDrop : false,
48398 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
48400 enableColumnMove : true,
48403 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
48405 enableColumnHide : true,
48408 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
48410 enableRowHeightSync : false,
48413 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
48418 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
48420 autoHeight : false,
48423 * @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.
48425 autoExpandColumn : false,
48428 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
48431 autoExpandMin : 50,
48434 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
48436 autoExpandMax : 1000,
48439 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
48444 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
48448 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
48458 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
48459 * of a fixed width. Default is false.
48462 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
48465 * Called once after all setup has been completed and the grid is ready to be rendered.
48466 * @return {Roo.grid.Grid} this
48468 render : function()
48470 var c = this.container;
48471 // try to detect autoHeight/width mode
48472 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
48473 this.autoHeight = true;
48475 var view = this.getView();
48478 c.on("click", this.onClick, this);
48479 c.on("dblclick", this.onDblClick, this);
48480 c.on("contextmenu", this.onContextMenu, this);
48481 c.on("keydown", this.onKeyDown, this);
48483 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
48485 this.getSelectionModel().init(this);
48490 this.loadMask = new Roo.LoadMask(this.container,
48491 Roo.apply({store:this.dataSource}, this.loadMask));
48495 if (this.toolbar && this.toolbar.xtype) {
48496 this.toolbar.container = this.getView().getHeaderPanel(true);
48497 this.toolbar = new Roo.Toolbar(this.toolbar);
48499 if (this.footer && this.footer.xtype) {
48500 this.footer.dataSource = this.getDataSource();
48501 this.footer.container = this.getView().getFooterPanel(true);
48502 this.footer = Roo.factory(this.footer, Roo);
48504 if (this.dropTarget && this.dropTarget.xtype) {
48505 delete this.dropTarget.xtype;
48506 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
48510 this.rendered = true;
48511 this.fireEvent('render', this);
48516 * Reconfigures the grid to use a different Store and Column Model.
48517 * The View will be bound to the new objects and refreshed.
48518 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
48519 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
48521 reconfigure : function(dataSource, colModel){
48523 this.loadMask.destroy();
48524 this.loadMask = new Roo.LoadMask(this.container,
48525 Roo.apply({store:dataSource}, this.loadMask));
48527 this.view.bind(dataSource, colModel);
48528 this.dataSource = dataSource;
48529 this.colModel = colModel;
48530 this.view.refresh(true);
48534 onKeyDown : function(e){
48535 this.fireEvent("keydown", e);
48539 * Destroy this grid.
48540 * @param {Boolean} removeEl True to remove the element
48542 destroy : function(removeEl, keepListeners){
48544 this.loadMask.destroy();
48546 var c = this.container;
48547 c.removeAllListeners();
48548 this.view.destroy();
48549 this.colModel.purgeListeners();
48550 if(!keepListeners){
48551 this.purgeListeners();
48554 if(removeEl === true){
48560 processEvent : function(name, e){
48561 this.fireEvent(name, e);
48562 var t = e.getTarget();
48564 var header = v.findHeaderIndex(t);
48565 if(header !== false){
48566 this.fireEvent("header" + name, this, header, e);
48568 var row = v.findRowIndex(t);
48569 var cell = v.findCellIndex(t);
48571 this.fireEvent("row" + name, this, row, e);
48572 if(cell !== false){
48573 this.fireEvent("cell" + name, this, row, cell, e);
48580 onClick : function(e){
48581 this.processEvent("click", e);
48585 onContextMenu : function(e, t){
48586 this.processEvent("contextmenu", e);
48590 onDblClick : function(e){
48591 this.processEvent("dblclick", e);
48595 walkCells : function(row, col, step, fn, scope){
48596 var cm = this.colModel, clen = cm.getColumnCount();
48597 var ds = this.dataSource, rlen = ds.getCount(), first = true;
48609 if(fn.call(scope || this, row, col, cm) === true){
48627 if(fn.call(scope || this, row, col, cm) === true){
48639 getSelections : function(){
48640 return this.selModel.getSelections();
48644 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
48645 * but if manual update is required this method will initiate it.
48647 autoSize : function(){
48649 this.view.layout();
48650 if(this.view.adjustForScroll){
48651 this.view.adjustForScroll();
48657 * Returns the grid's underlying element.
48658 * @return {Element} The element
48660 getGridEl : function(){
48661 return this.container;
48664 // private for compatibility, overridden by editor grid
48665 stopEditing : function(){},
48668 * Returns the grid's SelectionModel.
48669 * @return {SelectionModel}
48671 getSelectionModel : function(){
48672 if(!this.selModel){
48673 this.selModel = new Roo.grid.RowSelectionModel();
48675 return this.selModel;
48679 * Returns the grid's DataSource.
48680 * @return {DataSource}
48682 getDataSource : function(){
48683 return this.dataSource;
48687 * Returns the grid's ColumnModel.
48688 * @return {ColumnModel}
48690 getColumnModel : function(){
48691 return this.colModel;
48695 * Returns the grid's GridView object.
48696 * @return {GridView}
48698 getView : function(){
48700 this.view = new Roo.grid.GridView(this.viewConfig);
48705 * Called to get grid's drag proxy text, by default returns this.ddText.
48708 getDragDropText : function(){
48709 var count = this.selModel.getCount();
48710 return String.format(this.ddText, count, count == 1 ? '' : 's');
48714 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
48715 * %0 is replaced with the number of selected rows.
48718 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
48720 * Ext JS Library 1.1.1
48721 * Copyright(c) 2006-2007, Ext JS, LLC.
48723 * Originally Released Under LGPL - original licence link has changed is not relivant.
48726 * <script type="text/javascript">
48729 Roo.grid.AbstractGridView = function(){
48733 "beforerowremoved" : true,
48734 "beforerowsinserted" : true,
48735 "beforerefresh" : true,
48736 "rowremoved" : true,
48737 "rowsinserted" : true,
48738 "rowupdated" : true,
48741 Roo.grid.AbstractGridView.superclass.constructor.call(this);
48744 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
48745 rowClass : "x-grid-row",
48746 cellClass : "x-grid-cell",
48747 tdClass : "x-grid-td",
48748 hdClass : "x-grid-hd",
48749 splitClass : "x-grid-hd-split",
48751 init: function(grid){
48753 var cid = this.grid.getGridEl().id;
48754 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
48755 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
48756 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
48757 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
48760 getColumnRenderers : function(){
48761 var renderers = [];
48762 var cm = this.grid.colModel;
48763 var colCount = cm.getColumnCount();
48764 for(var i = 0; i < colCount; i++){
48765 renderers[i] = cm.getRenderer(i);
48770 getColumnIds : function(){
48772 var cm = this.grid.colModel;
48773 var colCount = cm.getColumnCount();
48774 for(var i = 0; i < colCount; i++){
48775 ids[i] = cm.getColumnId(i);
48780 getDataIndexes : function(){
48781 if(!this.indexMap){
48782 this.indexMap = this.buildIndexMap();
48784 return this.indexMap.colToData;
48787 getColumnIndexByDataIndex : function(dataIndex){
48788 if(!this.indexMap){
48789 this.indexMap = this.buildIndexMap();
48791 return this.indexMap.dataToCol[dataIndex];
48795 * Set a css style for a column dynamically.
48796 * @param {Number} colIndex The index of the column
48797 * @param {String} name The css property name
48798 * @param {String} value The css value
48800 setCSSStyle : function(colIndex, name, value){
48801 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
48802 Roo.util.CSS.updateRule(selector, name, value);
48805 generateRules : function(cm){
48806 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
48807 Roo.util.CSS.removeStyleSheet(rulesId);
48808 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48809 var cid = cm.getColumnId(i);
48810 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
48811 this.tdSelector, cid, " {\n}\n",
48812 this.hdSelector, cid, " {\n}\n",
48813 this.splitSelector, cid, " {\n}\n");
48815 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48819 * Ext JS Library 1.1.1
48820 * Copyright(c) 2006-2007, Ext JS, LLC.
48822 * Originally Released Under LGPL - original licence link has changed is not relivant.
48825 * <script type="text/javascript">
48829 // This is a support class used internally by the Grid components
48830 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
48832 this.view = grid.getView();
48833 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48834 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
48836 this.setHandleElId(Roo.id(hd));
48837 this.setOuterHandleElId(Roo.id(hd2));
48839 this.scroll = false;
48841 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
48843 getDragData : function(e){
48844 var t = Roo.lib.Event.getTarget(e);
48845 var h = this.view.findHeaderCell(t);
48847 return {ddel: h.firstChild, header:h};
48852 onInitDrag : function(e){
48853 this.view.headersDisabled = true;
48854 var clone = this.dragData.ddel.cloneNode(true);
48855 clone.id = Roo.id();
48856 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
48857 this.proxy.update(clone);
48861 afterValidDrop : function(){
48863 setTimeout(function(){
48864 v.headersDisabled = false;
48868 afterInvalidDrop : function(){
48870 setTimeout(function(){
48871 v.headersDisabled = false;
48877 * Ext JS Library 1.1.1
48878 * Copyright(c) 2006-2007, Ext JS, LLC.
48880 * Originally Released Under LGPL - original licence link has changed is not relivant.
48883 * <script type="text/javascript">
48886 // This is a support class used internally by the Grid components
48887 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
48889 this.view = grid.getView();
48890 // split the proxies so they don't interfere with mouse events
48891 this.proxyTop = Roo.DomHelper.append(document.body, {
48892 cls:"col-move-top", html:" "
48894 this.proxyBottom = Roo.DomHelper.append(document.body, {
48895 cls:"col-move-bottom", html:" "
48897 this.proxyTop.hide = this.proxyBottom.hide = function(){
48898 this.setLeftTop(-100,-100);
48899 this.setStyle("visibility", "hidden");
48901 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48902 // temporarily disabled
48903 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
48904 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
48906 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
48907 proxyOffsets : [-4, -9],
48908 fly: Roo.Element.fly,
48910 getTargetFromEvent : function(e){
48911 var t = Roo.lib.Event.getTarget(e);
48912 var cindex = this.view.findCellIndex(t);
48913 if(cindex !== false){
48914 return this.view.getHeaderCell(cindex);
48919 nextVisible : function(h){
48920 var v = this.view, cm = this.grid.colModel;
48923 if(!cm.isHidden(v.getCellIndex(h))){
48931 prevVisible : function(h){
48932 var v = this.view, cm = this.grid.colModel;
48935 if(!cm.isHidden(v.getCellIndex(h))){
48943 positionIndicator : function(h, n, e){
48944 var x = Roo.lib.Event.getPageX(e);
48945 var r = Roo.lib.Dom.getRegion(n.firstChild);
48946 var px, pt, py = r.top + this.proxyOffsets[1];
48947 if((r.right - x) <= (r.right-r.left)/2){
48948 px = r.right+this.view.borderWidth;
48954 var oldIndex = this.view.getCellIndex(h);
48955 var newIndex = this.view.getCellIndex(n);
48957 if(this.grid.colModel.isFixed(newIndex)){
48961 var locked = this.grid.colModel.isLocked(newIndex);
48966 if(oldIndex < newIndex){
48969 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
48972 px += this.proxyOffsets[0];
48973 this.proxyTop.setLeftTop(px, py);
48974 this.proxyTop.show();
48975 if(!this.bottomOffset){
48976 this.bottomOffset = this.view.mainHd.getHeight();
48978 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
48979 this.proxyBottom.show();
48983 onNodeEnter : function(n, dd, e, data){
48984 if(data.header != n){
48985 this.positionIndicator(data.header, n, e);
48989 onNodeOver : function(n, dd, e, data){
48990 var result = false;
48991 if(data.header != n){
48992 result = this.positionIndicator(data.header, n, e);
48995 this.proxyTop.hide();
48996 this.proxyBottom.hide();
48998 return result ? this.dropAllowed : this.dropNotAllowed;
49001 onNodeOut : function(n, dd, e, data){
49002 this.proxyTop.hide();
49003 this.proxyBottom.hide();
49006 onNodeDrop : function(n, dd, e, data){
49007 var h = data.header;
49009 var cm = this.grid.colModel;
49010 var x = Roo.lib.Event.getPageX(e);
49011 var r = Roo.lib.Dom.getRegion(n.firstChild);
49012 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
49013 var oldIndex = this.view.getCellIndex(h);
49014 var newIndex = this.view.getCellIndex(n);
49015 var locked = cm.isLocked(newIndex);
49019 if(oldIndex < newIndex){
49022 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
49025 cm.setLocked(oldIndex, locked, true);
49026 cm.moveColumn(oldIndex, newIndex);
49027 this.grid.fireEvent("columnmove", oldIndex, newIndex);
49035 * Ext JS Library 1.1.1
49036 * Copyright(c) 2006-2007, Ext JS, LLC.
49038 * Originally Released Under LGPL - original licence link has changed is not relivant.
49041 * <script type="text/javascript">
49045 * @class Roo.grid.GridView
49046 * @extends Roo.util.Observable
49049 * @param {Object} config
49051 Roo.grid.GridView = function(config){
49052 Roo.grid.GridView.superclass.constructor.call(this);
49055 Roo.apply(this, config);
49058 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
49061 rowClass : "x-grid-row",
49063 cellClass : "x-grid-col",
49065 tdClass : "x-grid-td",
49067 hdClass : "x-grid-hd",
49069 splitClass : "x-grid-split",
49071 sortClasses : ["sort-asc", "sort-desc"],
49073 enableMoveAnim : false,
49077 dh : Roo.DomHelper,
49079 fly : Roo.Element.fly,
49081 css : Roo.util.CSS,
49087 scrollIncrement : 22,
49089 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
49091 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
49093 bind : function(ds, cm){
49095 this.ds.un("load", this.onLoad, this);
49096 this.ds.un("datachanged", this.onDataChange, this);
49097 this.ds.un("add", this.onAdd, this);
49098 this.ds.un("remove", this.onRemove, this);
49099 this.ds.un("update", this.onUpdate, this);
49100 this.ds.un("clear", this.onClear, this);
49103 ds.on("load", this.onLoad, this);
49104 ds.on("datachanged", this.onDataChange, this);
49105 ds.on("add", this.onAdd, this);
49106 ds.on("remove", this.onRemove, this);
49107 ds.on("update", this.onUpdate, this);
49108 ds.on("clear", this.onClear, this);
49113 this.cm.un("widthchange", this.onColWidthChange, this);
49114 this.cm.un("headerchange", this.onHeaderChange, this);
49115 this.cm.un("hiddenchange", this.onHiddenChange, this);
49116 this.cm.un("columnmoved", this.onColumnMove, this);
49117 this.cm.un("columnlockchange", this.onColumnLock, this);
49120 this.generateRules(cm);
49121 cm.on("widthchange", this.onColWidthChange, this);
49122 cm.on("headerchange", this.onHeaderChange, this);
49123 cm.on("hiddenchange", this.onHiddenChange, this);
49124 cm.on("columnmoved", this.onColumnMove, this);
49125 cm.on("columnlockchange", this.onColumnLock, this);
49130 init: function(grid){
49131 Roo.grid.GridView.superclass.init.call(this, grid);
49133 this.bind(grid.dataSource, grid.colModel);
49135 grid.on("headerclick", this.handleHeaderClick, this);
49137 if(grid.trackMouseOver){
49138 grid.on("mouseover", this.onRowOver, this);
49139 grid.on("mouseout", this.onRowOut, this);
49141 grid.cancelTextSelection = function(){};
49142 this.gridId = grid.id;
49144 var tpls = this.templates || {};
49147 tpls.master = new Roo.Template(
49148 '<div class="x-grid" hidefocus="true">',
49149 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
49150 '<div class="x-grid-topbar"></div>',
49151 '<div class="x-grid-scroller"><div></div></div>',
49152 '<div class="x-grid-locked">',
49153 '<div class="x-grid-header">{lockedHeader}</div>',
49154 '<div class="x-grid-body">{lockedBody}</div>',
49156 '<div class="x-grid-viewport">',
49157 '<div class="x-grid-header">{header}</div>',
49158 '<div class="x-grid-body">{body}</div>',
49160 '<div class="x-grid-bottombar"></div>',
49162 '<div class="x-grid-resize-proxy"> </div>',
49165 tpls.master.disableformats = true;
49169 tpls.header = new Roo.Template(
49170 '<table border="0" cellspacing="0" cellpadding="0">',
49171 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
49174 tpls.header.disableformats = true;
49176 tpls.header.compile();
49179 tpls.hcell = new Roo.Template(
49180 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
49181 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
49184 tpls.hcell.disableFormats = true;
49186 tpls.hcell.compile();
49189 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
49190 tpls.hsplit.disableFormats = true;
49192 tpls.hsplit.compile();
49195 tpls.body = new Roo.Template(
49196 '<table border="0" cellspacing="0" cellpadding="0">',
49197 "<tbody>{rows}</tbody>",
49200 tpls.body.disableFormats = true;
49202 tpls.body.compile();
49205 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
49206 tpls.row.disableFormats = true;
49208 tpls.row.compile();
49211 tpls.cell = new Roo.Template(
49212 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
49213 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
49216 tpls.cell.disableFormats = true;
49218 tpls.cell.compile();
49220 this.templates = tpls;
49223 // remap these for backwards compat
49224 onColWidthChange : function(){
49225 this.updateColumns.apply(this, arguments);
49227 onHeaderChange : function(){
49228 this.updateHeaders.apply(this, arguments);
49230 onHiddenChange : function(){
49231 this.handleHiddenChange.apply(this, arguments);
49233 onColumnMove : function(){
49234 this.handleColumnMove.apply(this, arguments);
49236 onColumnLock : function(){
49237 this.handleLockChange.apply(this, arguments);
49240 onDataChange : function(){
49242 this.updateHeaderSortState();
49245 onClear : function(){
49249 onUpdate : function(ds, record){
49250 this.refreshRow(record);
49253 refreshRow : function(record){
49254 var ds = this.ds, index;
49255 if(typeof record == 'number'){
49257 record = ds.getAt(index);
49259 index = ds.indexOf(record);
49261 this.insertRows(ds, index, index, true);
49262 this.onRemove(ds, record, index+1, true);
49263 this.syncRowHeights(index, index);
49265 this.fireEvent("rowupdated", this, index, record);
49268 onAdd : function(ds, records, index){
49269 this.insertRows(ds, index, index + (records.length-1));
49272 onRemove : function(ds, record, index, isUpdate){
49273 if(isUpdate !== true){
49274 this.fireEvent("beforerowremoved", this, index, record);
49276 var bt = this.getBodyTable(), lt = this.getLockedTable();
49277 if(bt.rows[index]){
49278 bt.firstChild.removeChild(bt.rows[index]);
49280 if(lt.rows[index]){
49281 lt.firstChild.removeChild(lt.rows[index]);
49283 if(isUpdate !== true){
49284 this.stripeRows(index);
49285 this.syncRowHeights(index, index);
49287 this.fireEvent("rowremoved", this, index, record);
49291 onLoad : function(){
49292 this.scrollToTop();
49296 * Scrolls the grid to the top
49298 scrollToTop : function(){
49300 this.scroller.dom.scrollTop = 0;
49306 * Gets a panel in the header of the grid that can be used for toolbars etc.
49307 * After modifying the contents of this panel a call to grid.autoSize() may be
49308 * required to register any changes in size.
49309 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
49310 * @return Roo.Element
49312 getHeaderPanel : function(doShow){
49314 this.headerPanel.show();
49316 return this.headerPanel;
49320 * Gets a panel in the footer of the grid that can be used for toolbars etc.
49321 * After modifying the contents of this panel a call to grid.autoSize() may be
49322 * required to register any changes in size.
49323 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
49324 * @return Roo.Element
49326 getFooterPanel : function(doShow){
49328 this.footerPanel.show();
49330 return this.footerPanel;
49333 initElements : function(){
49334 var E = Roo.Element;
49335 var el = this.grid.getGridEl().dom.firstChild;
49336 var cs = el.childNodes;
49338 this.el = new E(el);
49340 this.focusEl = new E(el.firstChild);
49341 this.focusEl.swallowEvent("click", true);
49343 this.headerPanel = new E(cs[1]);
49344 this.headerPanel.enableDisplayMode("block");
49346 this.scroller = new E(cs[2]);
49347 this.scrollSizer = new E(this.scroller.dom.firstChild);
49349 this.lockedWrap = new E(cs[3]);
49350 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
49351 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
49353 this.mainWrap = new E(cs[4]);
49354 this.mainHd = new E(this.mainWrap.dom.firstChild);
49355 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
49357 this.footerPanel = new E(cs[5]);
49358 this.footerPanel.enableDisplayMode("block");
49360 this.resizeProxy = new E(cs[6]);
49362 this.headerSelector = String.format(
49363 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
49364 this.lockedHd.id, this.mainHd.id
49367 this.splitterSelector = String.format(
49368 '#{0} div.x-grid-split, #{1} div.x-grid-split',
49369 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
49372 idToCssName : function(s)
49374 return s.replace(/[^a-z0-9]+/ig, '-');
49377 getHeaderCell : function(index){
49378 return Roo.DomQuery.select(this.headerSelector)[index];
49381 getHeaderCellMeasure : function(index){
49382 return this.getHeaderCell(index).firstChild;
49385 getHeaderCellText : function(index){
49386 return this.getHeaderCell(index).firstChild.firstChild;
49389 getLockedTable : function(){
49390 return this.lockedBody.dom.firstChild;
49393 getBodyTable : function(){
49394 return this.mainBody.dom.firstChild;
49397 getLockedRow : function(index){
49398 return this.getLockedTable().rows[index];
49401 getRow : function(index){
49402 return this.getBodyTable().rows[index];
49405 getRowComposite : function(index){
49407 this.rowEl = new Roo.CompositeElementLite();
49409 var els = [], lrow, mrow;
49410 if(lrow = this.getLockedRow(index)){
49413 if(mrow = this.getRow(index)){
49416 this.rowEl.elements = els;
49420 * Gets the 'td' of the cell
49422 * @param {Integer} rowIndex row to select
49423 * @param {Integer} colIndex column to select
49427 getCell : function(rowIndex, colIndex){
49428 var locked = this.cm.getLockedCount();
49430 if(colIndex < locked){
49431 source = this.lockedBody.dom.firstChild;
49433 source = this.mainBody.dom.firstChild;
49434 colIndex -= locked;
49436 return source.rows[rowIndex].childNodes[colIndex];
49439 getCellText : function(rowIndex, colIndex){
49440 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
49443 getCellBox : function(cell){
49444 var b = this.fly(cell).getBox();
49445 if(Roo.isOpera){ // opera fails to report the Y
49446 b.y = cell.offsetTop + this.mainBody.getY();
49451 getCellIndex : function(cell){
49452 var id = String(cell.className).match(this.cellRE);
49454 return parseInt(id[1], 10);
49459 findHeaderIndex : function(n){
49460 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
49461 return r ? this.getCellIndex(r) : false;
49464 findHeaderCell : function(n){
49465 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
49466 return r ? r : false;
49469 findRowIndex : function(n){
49473 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
49474 return r ? r.rowIndex : false;
49477 findCellIndex : function(node){
49478 var stop = this.el.dom;
49479 while(node && node != stop){
49480 if(this.findRE.test(node.className)){
49481 return this.getCellIndex(node);
49483 node = node.parentNode;
49488 getColumnId : function(index){
49489 return this.cm.getColumnId(index);
49492 getSplitters : function()
49494 if(this.splitterSelector){
49495 return Roo.DomQuery.select(this.splitterSelector);
49501 getSplitter : function(index){
49502 return this.getSplitters()[index];
49505 onRowOver : function(e, t){
49507 if((row = this.findRowIndex(t)) !== false){
49508 this.getRowComposite(row).addClass("x-grid-row-over");
49512 onRowOut : function(e, t){
49514 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
49515 this.getRowComposite(row).removeClass("x-grid-row-over");
49519 renderHeaders : function(){
49521 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
49522 var cb = [], lb = [], sb = [], lsb = [], p = {};
49523 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49524 p.cellId = "x-grid-hd-0-" + i;
49525 p.splitId = "x-grid-csplit-0-" + i;
49526 p.id = cm.getColumnId(i);
49527 p.title = cm.getColumnTooltip(i) || "";
49528 p.value = cm.getColumnHeader(i) || "";
49529 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
49530 if(!cm.isLocked(i)){
49531 cb[cb.length] = ct.apply(p);
49532 sb[sb.length] = st.apply(p);
49534 lb[lb.length] = ct.apply(p);
49535 lsb[lsb.length] = st.apply(p);
49538 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
49539 ht.apply({cells: cb.join(""), splits:sb.join("")})];
49542 updateHeaders : function(){
49543 var html = this.renderHeaders();
49544 this.lockedHd.update(html[0]);
49545 this.mainHd.update(html[1]);
49549 * Focuses the specified row.
49550 * @param {Number} row The row index
49552 focusRow : function(row)
49554 //Roo.log('GridView.focusRow');
49555 var x = this.scroller.dom.scrollLeft;
49556 this.focusCell(row, 0, false);
49557 this.scroller.dom.scrollLeft = x;
49561 * Focuses the specified cell.
49562 * @param {Number} row The row index
49563 * @param {Number} col The column index
49564 * @param {Boolean} hscroll false to disable horizontal scrolling
49566 focusCell : function(row, col, hscroll)
49568 //Roo.log('GridView.focusCell');
49569 var el = this.ensureVisible(row, col, hscroll);
49570 this.focusEl.alignTo(el, "tl-tl");
49572 this.focusEl.focus();
49574 this.focusEl.focus.defer(1, this.focusEl);
49579 * Scrolls the specified cell into view
49580 * @param {Number} row The row index
49581 * @param {Number} col The column index
49582 * @param {Boolean} hscroll false to disable horizontal scrolling
49584 ensureVisible : function(row, col, hscroll)
49586 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
49587 //return null; //disable for testing.
49588 if(typeof row != "number"){
49589 row = row.rowIndex;
49591 if(row < 0 && row >= this.ds.getCount()){
49594 col = (col !== undefined ? col : 0);
49595 var cm = this.grid.colModel;
49596 while(cm.isHidden(col)){
49600 var el = this.getCell(row, col);
49604 var c = this.scroller.dom;
49606 var ctop = parseInt(el.offsetTop, 10);
49607 var cleft = parseInt(el.offsetLeft, 10);
49608 var cbot = ctop + el.offsetHeight;
49609 var cright = cleft + el.offsetWidth;
49611 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
49612 var stop = parseInt(c.scrollTop, 10);
49613 var sleft = parseInt(c.scrollLeft, 10);
49614 var sbot = stop + ch;
49615 var sright = sleft + c.clientWidth;
49617 Roo.log('GridView.ensureVisible:' +
49619 ' c.clientHeight:' + c.clientHeight +
49620 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
49628 c.scrollTop = ctop;
49629 //Roo.log("set scrolltop to ctop DISABLE?");
49630 }else if(cbot > sbot){
49631 //Roo.log("set scrolltop to cbot-ch");
49632 c.scrollTop = cbot-ch;
49635 if(hscroll !== false){
49637 c.scrollLeft = cleft;
49638 }else if(cright > sright){
49639 c.scrollLeft = cright-c.clientWidth;
49646 updateColumns : function(){
49647 this.grid.stopEditing();
49648 var cm = this.grid.colModel, colIds = this.getColumnIds();
49649 //var totalWidth = cm.getTotalWidth();
49651 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49652 //if(cm.isHidden(i)) continue;
49653 var w = cm.getColumnWidth(i);
49654 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
49655 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
49657 this.updateSplitters();
49660 generateRules : function(cm){
49661 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
49662 Roo.util.CSS.removeStyleSheet(rulesId);
49663 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49664 var cid = cm.getColumnId(i);
49666 if(cm.config[i].align){
49667 align = 'text-align:'+cm.config[i].align+';';
49670 if(cm.isHidden(i)){
49671 hidden = 'display:none;';
49673 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
49675 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
49676 this.hdSelector, cid, " {\n", align, width, "}\n",
49677 this.tdSelector, cid, " {\n",hidden,"\n}\n",
49678 this.splitSelector, cid, " {\n", hidden , "\n}\n");
49680 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
49683 updateSplitters : function(){
49684 var cm = this.cm, s = this.getSplitters();
49685 if(s){ // splitters not created yet
49686 var pos = 0, locked = true;
49687 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49688 if(cm.isHidden(i)) continue;
49689 var w = cm.getColumnWidth(i); // make sure it's a number
49690 if(!cm.isLocked(i) && locked){
49695 s[i].style.left = (pos-this.splitOffset) + "px";
49700 handleHiddenChange : function(colModel, colIndex, hidden){
49702 this.hideColumn(colIndex);
49704 this.unhideColumn(colIndex);
49708 hideColumn : function(colIndex){
49709 var cid = this.getColumnId(colIndex);
49710 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
49711 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
49713 this.updateHeaders();
49715 this.updateSplitters();
49719 unhideColumn : function(colIndex){
49720 var cid = this.getColumnId(colIndex);
49721 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
49722 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
49725 this.updateHeaders();
49727 this.updateSplitters();
49731 insertRows : function(dm, firstRow, lastRow, isUpdate){
49732 if(firstRow == 0 && lastRow == dm.getCount()-1){
49736 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
49738 var s = this.getScrollState();
49739 var markup = this.renderRows(firstRow, lastRow);
49740 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
49741 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
49742 this.restoreScroll(s);
49744 this.fireEvent("rowsinserted", this, firstRow, lastRow);
49745 this.syncRowHeights(firstRow, lastRow);
49746 this.stripeRows(firstRow);
49752 bufferRows : function(markup, target, index){
49753 var before = null, trows = target.rows, tbody = target.tBodies[0];
49754 if(index < trows.length){
49755 before = trows[index];
49757 var b = document.createElement("div");
49758 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
49759 var rows = b.firstChild.rows;
49760 for(var i = 0, len = rows.length; i < len; i++){
49762 tbody.insertBefore(rows[0], before);
49764 tbody.appendChild(rows[0]);
49771 deleteRows : function(dm, firstRow, lastRow){
49772 if(dm.getRowCount()<1){
49773 this.fireEvent("beforerefresh", this);
49774 this.mainBody.update("");
49775 this.lockedBody.update("");
49776 this.fireEvent("refresh", this);
49778 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
49779 var bt = this.getBodyTable();
49780 var tbody = bt.firstChild;
49781 var rows = bt.rows;
49782 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
49783 tbody.removeChild(rows[firstRow]);
49785 this.stripeRows(firstRow);
49786 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
49790 updateRows : function(dataSource, firstRow, lastRow){
49791 var s = this.getScrollState();
49793 this.restoreScroll(s);
49796 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
49800 this.updateHeaderSortState();
49803 getScrollState : function(){
49805 var sb = this.scroller.dom;
49806 return {left: sb.scrollLeft, top: sb.scrollTop};
49809 stripeRows : function(startRow){
49810 if(!this.grid.stripeRows || this.ds.getCount() < 1){
49813 startRow = startRow || 0;
49814 var rows = this.getBodyTable().rows;
49815 var lrows = this.getLockedTable().rows;
49816 var cls = ' x-grid-row-alt ';
49817 for(var i = startRow, len = rows.length; i < len; i++){
49818 var row = rows[i], lrow = lrows[i];
49819 var isAlt = ((i+1) % 2 == 0);
49820 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
49821 if(isAlt == hasAlt){
49825 row.className += " x-grid-row-alt";
49827 row.className = row.className.replace("x-grid-row-alt", "");
49830 lrow.className = row.className;
49835 restoreScroll : function(state){
49836 //Roo.log('GridView.restoreScroll');
49837 var sb = this.scroller.dom;
49838 sb.scrollLeft = state.left;
49839 sb.scrollTop = state.top;
49843 syncScroll : function(){
49844 //Roo.log('GridView.syncScroll');
49845 var sb = this.scroller.dom;
49846 var sh = this.mainHd.dom;
49847 var bs = this.mainBody.dom;
49848 var lv = this.lockedBody.dom;
49849 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
49850 lv.scrollTop = bs.scrollTop = sb.scrollTop;
49853 handleScroll : function(e){
49855 var sb = this.scroller.dom;
49856 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
49860 handleWheel : function(e){
49861 var d = e.getWheelDelta();
49862 this.scroller.dom.scrollTop -= d*22;
49863 // set this here to prevent jumpy scrolling on large tables
49864 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
49868 renderRows : function(startRow, endRow){
49869 // pull in all the crap needed to render rows
49870 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
49871 var colCount = cm.getColumnCount();
49873 if(ds.getCount() < 1){
49877 // build a map for all the columns
49879 for(var i = 0; i < colCount; i++){
49880 var name = cm.getDataIndex(i);
49882 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
49883 renderer : cm.getRenderer(i),
49884 id : cm.getColumnId(i),
49885 locked : cm.isLocked(i)
49889 startRow = startRow || 0;
49890 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
49892 // records to render
49893 var rs = ds.getRange(startRow, endRow);
49895 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
49898 // As much as I hate to duplicate code, this was branched because FireFox really hates
49899 // [].join("") on strings. The performance difference was substantial enough to
49900 // branch this function
49901 doRender : Roo.isGecko ?
49902 function(cs, rs, ds, startRow, colCount, stripe){
49903 var ts = this.templates, ct = ts.cell, rt = ts.row;
49905 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49907 var hasListener = this.grid.hasListener('rowclass');
49909 for(var j = 0, len = rs.length; j < len; j++){
49910 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
49911 for(var i = 0; i < colCount; i++){
49913 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49915 p.css = p.attr = "";
49916 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49917 if(p.value == undefined || p.value === "") p.value = " ";
49918 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49919 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49921 var markup = ct.apply(p);
49929 if(stripe && ((rowIndex+1) % 2 == 0)){
49930 alt.push("x-grid-row-alt")
49933 alt.push( " x-grid-dirty-row");
49936 if(this.getRowClass){
49937 alt.push(this.getRowClass(r, rowIndex));
49943 rowIndex : rowIndex,
49946 this.grid.fireEvent('rowclass', this, rowcfg);
49947 alt.push(rowcfg.rowClass);
49949 rp.alt = alt.join(" ");
49950 lbuf+= rt.apply(rp);
49952 buf+= rt.apply(rp);
49954 return [lbuf, buf];
49956 function(cs, rs, ds, startRow, colCount, stripe){
49957 var ts = this.templates, ct = ts.cell, rt = ts.row;
49959 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49960 var hasListener = this.grid.hasListener('rowclass');
49963 for(var j = 0, len = rs.length; j < len; j++){
49964 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
49965 for(var i = 0; i < colCount; i++){
49967 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49969 p.css = p.attr = "";
49970 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49971 if(p.value == undefined || p.value === "") p.value = " ";
49972 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49973 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49976 var markup = ct.apply(p);
49978 cb[cb.length] = markup;
49980 lcb[lcb.length] = markup;
49984 if(stripe && ((rowIndex+1) % 2 == 0)){
49985 alt.push( "x-grid-row-alt");
49988 alt.push(" x-grid-dirty-row");
49991 if(this.getRowClass){
49992 alt.push( this.getRowClass(r, rowIndex));
49998 rowIndex : rowIndex,
50001 this.grid.fireEvent('rowclass', this, rowcfg);
50002 alt.push(rowcfg.rowClass);
50004 rp.alt = alt.join(" ");
50005 rp.cells = lcb.join("");
50006 lbuf[lbuf.length] = rt.apply(rp);
50007 rp.cells = cb.join("");
50008 buf[buf.length] = rt.apply(rp);
50010 return [lbuf.join(""), buf.join("")];
50013 renderBody : function(){
50014 var markup = this.renderRows();
50015 var bt = this.templates.body;
50016 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
50020 * Refreshes the grid
50021 * @param {Boolean} headersToo
50023 refresh : function(headersToo){
50024 this.fireEvent("beforerefresh", this);
50025 this.grid.stopEditing();
50026 var result = this.renderBody();
50027 this.lockedBody.update(result[0]);
50028 this.mainBody.update(result[1]);
50029 if(headersToo === true){
50030 this.updateHeaders();
50031 this.updateColumns();
50032 this.updateSplitters();
50033 this.updateHeaderSortState();
50035 this.syncRowHeights();
50037 this.fireEvent("refresh", this);
50040 handleColumnMove : function(cm, oldIndex, newIndex){
50041 this.indexMap = null;
50042 var s = this.getScrollState();
50043 this.refresh(true);
50044 this.restoreScroll(s);
50045 this.afterMove(newIndex);
50048 afterMove : function(colIndex){
50049 if(this.enableMoveAnim && Roo.enableFx){
50050 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
50052 // if multisort - fix sortOrder, and reload..
50053 if (this.grid.dataSource.multiSort) {
50054 // the we can call sort again..
50055 var dm = this.grid.dataSource;
50056 var cm = this.grid.colModel;
50058 for(var i = 0; i < cm.config.length; i++ ) {
50060 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
50061 continue; // dont' bother, it's not in sort list or being set.
50064 so.push(cm.config[i].dataIndex);
50067 dm.load(dm.lastOptions);
50074 updateCell : function(dm, rowIndex, dataIndex){
50075 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
50076 if(typeof colIndex == "undefined"){ // not present in grid
50079 var cm = this.grid.colModel;
50080 var cell = this.getCell(rowIndex, colIndex);
50081 var cellText = this.getCellText(rowIndex, colIndex);
50084 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
50085 id : cm.getColumnId(colIndex),
50086 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
50088 var renderer = cm.getRenderer(colIndex);
50089 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
50090 if(typeof val == "undefined" || val === "") val = " ";
50091 cellText.innerHTML = val;
50092 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
50093 this.syncRowHeights(rowIndex, rowIndex);
50096 calcColumnWidth : function(colIndex, maxRowsToMeasure){
50098 if(this.grid.autoSizeHeaders){
50099 var h = this.getHeaderCellMeasure(colIndex);
50100 maxWidth = Math.max(maxWidth, h.scrollWidth);
50103 if(this.cm.isLocked(colIndex)){
50104 tb = this.getLockedTable();
50107 tb = this.getBodyTable();
50108 index = colIndex - this.cm.getLockedCount();
50111 var rows = tb.rows;
50112 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
50113 for(var i = 0; i < stopIndex; i++){
50114 var cell = rows[i].childNodes[index].firstChild;
50115 maxWidth = Math.max(maxWidth, cell.scrollWidth);
50118 return maxWidth + /*margin for error in IE*/ 5;
50121 * Autofit a column to its content.
50122 * @param {Number} colIndex
50123 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
50125 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
50126 if(this.cm.isHidden(colIndex)){
50127 return; // can't calc a hidden column
50130 var cid = this.cm.getColumnId(colIndex);
50131 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
50132 if(this.grid.autoSizeHeaders){
50133 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
50136 var newWidth = this.calcColumnWidth(colIndex);
50137 this.cm.setColumnWidth(colIndex,
50138 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
50139 if(!suppressEvent){
50140 this.grid.fireEvent("columnresize", colIndex, newWidth);
50145 * Autofits all columns to their content and then expands to fit any extra space in the grid
50147 autoSizeColumns : function(){
50148 var cm = this.grid.colModel;
50149 var colCount = cm.getColumnCount();
50150 for(var i = 0; i < colCount; i++){
50151 this.autoSizeColumn(i, true, true);
50153 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
50156 this.updateColumns();
50162 * Autofits all columns to the grid's width proportionate with their current size
50163 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
50165 fitColumns : function(reserveScrollSpace){
50166 var cm = this.grid.colModel;
50167 var colCount = cm.getColumnCount();
50171 for (i = 0; i < colCount; i++){
50172 if(!cm.isHidden(i) && !cm.isFixed(i)){
50173 w = cm.getColumnWidth(i);
50179 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
50180 if(reserveScrollSpace){
50183 var frac = (avail - cm.getTotalWidth())/width;
50184 while (cols.length){
50187 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
50189 this.updateColumns();
50193 onRowSelect : function(rowIndex){
50194 var row = this.getRowComposite(rowIndex);
50195 row.addClass("x-grid-row-selected");
50198 onRowDeselect : function(rowIndex){
50199 var row = this.getRowComposite(rowIndex);
50200 row.removeClass("x-grid-row-selected");
50203 onCellSelect : function(row, col){
50204 var cell = this.getCell(row, col);
50206 Roo.fly(cell).addClass("x-grid-cell-selected");
50210 onCellDeselect : function(row, col){
50211 var cell = this.getCell(row, col);
50213 Roo.fly(cell).removeClass("x-grid-cell-selected");
50217 updateHeaderSortState : function(){
50219 // sort state can be single { field: xxx, direction : yyy}
50220 // or { xxx=>ASC , yyy : DESC ..... }
50223 if (!this.ds.multiSort) {
50224 var state = this.ds.getSortState();
50228 mstate[state.field] = state.direction;
50229 // FIXME... - this is not used here.. but might be elsewhere..
50230 this.sortState = state;
50233 mstate = this.ds.sortToggle;
50235 //remove existing sort classes..
50237 var sc = this.sortClasses;
50238 var hds = this.el.select(this.headerSelector).removeClass(sc);
50240 for(var f in mstate) {
50242 var sortColumn = this.cm.findColumnIndex(f);
50244 if(sortColumn != -1){
50245 var sortDir = mstate[f];
50246 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
50255 handleHeaderClick : function(g, index){
50256 if(this.headersDisabled){
50259 var dm = g.dataSource, cm = g.colModel;
50260 if(!cm.isSortable(index)){
50265 if (dm.multiSort) {
50266 // update the sortOrder
50268 for(var i = 0; i < cm.config.length; i++ ) {
50270 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
50271 continue; // dont' bother, it's not in sort list or being set.
50274 so.push(cm.config[i].dataIndex);
50280 dm.sort(cm.getDataIndex(index));
50284 destroy : function(){
50286 this.colMenu.removeAll();
50287 Roo.menu.MenuMgr.unregister(this.colMenu);
50288 this.colMenu.getEl().remove();
50289 delete this.colMenu;
50292 this.hmenu.removeAll();
50293 Roo.menu.MenuMgr.unregister(this.hmenu);
50294 this.hmenu.getEl().remove();
50297 if(this.grid.enableColumnMove){
50298 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
50300 for(var dd in dds){
50301 if(!dds[dd].config.isTarget && dds[dd].dragElId){
50302 var elid = dds[dd].dragElId;
50304 Roo.get(elid).remove();
50305 } else if(dds[dd].config.isTarget){
50306 dds[dd].proxyTop.remove();
50307 dds[dd].proxyBottom.remove();
50310 if(Roo.dd.DDM.locationCache[dd]){
50311 delete Roo.dd.DDM.locationCache[dd];
50314 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
50317 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
50318 this.bind(null, null);
50319 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
50322 handleLockChange : function(){
50323 this.refresh(true);
50326 onDenyColumnLock : function(){
50330 onDenyColumnHide : function(){
50334 handleHdMenuClick : function(item){
50335 var index = this.hdCtxIndex;
50336 var cm = this.cm, ds = this.ds;
50339 ds.sort(cm.getDataIndex(index), "ASC");
50342 ds.sort(cm.getDataIndex(index), "DESC");
50345 var lc = cm.getLockedCount();
50346 if(cm.getColumnCount(true) <= lc+1){
50347 this.onDenyColumnLock();
50351 cm.setLocked(index, true, true);
50352 cm.moveColumn(index, lc);
50353 this.grid.fireEvent("columnmove", index, lc);
50355 cm.setLocked(index, true);
50359 var lc = cm.getLockedCount();
50360 if((lc-1) != index){
50361 cm.setLocked(index, false, true);
50362 cm.moveColumn(index, lc-1);
50363 this.grid.fireEvent("columnmove", index, lc-1);
50365 cm.setLocked(index, false);
50369 index = cm.getIndexById(item.id.substr(4));
50371 if(item.checked && cm.getColumnCount(true) <= 1){
50372 this.onDenyColumnHide();
50375 cm.setHidden(index, item.checked);
50381 beforeColMenuShow : function(){
50382 var cm = this.cm, colCount = cm.getColumnCount();
50383 this.colMenu.removeAll();
50384 for(var i = 0; i < colCount; i++){
50385 this.colMenu.add(new Roo.menu.CheckItem({
50386 id: "col-"+cm.getColumnId(i),
50387 text: cm.getColumnHeader(i),
50388 checked: !cm.isHidden(i),
50394 handleHdCtx : function(g, index, e){
50396 var hd = this.getHeaderCell(index);
50397 this.hdCtxIndex = index;
50398 var ms = this.hmenu.items, cm = this.cm;
50399 ms.get("asc").setDisabled(!cm.isSortable(index));
50400 ms.get("desc").setDisabled(!cm.isSortable(index));
50401 if(this.grid.enableColLock !== false){
50402 ms.get("lock").setDisabled(cm.isLocked(index));
50403 ms.get("unlock").setDisabled(!cm.isLocked(index));
50405 this.hmenu.show(hd, "tl-bl");
50408 handleHdOver : function(e){
50409 var hd = this.findHeaderCell(e.getTarget());
50410 if(hd && !this.headersDisabled){
50411 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
50412 this.fly(hd).addClass("x-grid-hd-over");
50417 handleHdOut : function(e){
50418 var hd = this.findHeaderCell(e.getTarget());
50420 this.fly(hd).removeClass("x-grid-hd-over");
50424 handleSplitDblClick : function(e, t){
50425 var i = this.getCellIndex(t);
50426 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
50427 this.autoSizeColumn(i, true);
50432 render : function(){
50435 var colCount = cm.getColumnCount();
50437 if(this.grid.monitorWindowResize === true){
50438 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50440 var header = this.renderHeaders();
50441 var body = this.templates.body.apply({rows:""});
50442 var html = this.templates.master.apply({
50445 lockedHeader: header[0],
50449 //this.updateColumns();
50451 this.grid.getGridEl().dom.innerHTML = html;
50453 this.initElements();
50455 // a kludge to fix the random scolling effect in webkit
50456 this.el.on("scroll", function() {
50457 this.el.dom.scrollTop=0; // hopefully not recursive..
50460 this.scroller.on("scroll", this.handleScroll, this);
50461 this.lockedBody.on("mousewheel", this.handleWheel, this);
50462 this.mainBody.on("mousewheel", this.handleWheel, this);
50464 this.mainHd.on("mouseover", this.handleHdOver, this);
50465 this.mainHd.on("mouseout", this.handleHdOut, this);
50466 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
50467 {delegate: "."+this.splitClass});
50469 this.lockedHd.on("mouseover", this.handleHdOver, this);
50470 this.lockedHd.on("mouseout", this.handleHdOut, this);
50471 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
50472 {delegate: "."+this.splitClass});
50474 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
50475 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50478 this.updateSplitters();
50480 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
50481 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50482 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50485 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
50486 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
50488 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
50489 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
50491 if(this.grid.enableColLock !== false){
50492 this.hmenu.add('-',
50493 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
50494 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
50497 if(this.grid.enableColumnHide !== false){
50499 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
50500 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
50501 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
50503 this.hmenu.add('-',
50504 {id:"columns", text: this.columnsText, menu: this.colMenu}
50507 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
50509 this.grid.on("headercontextmenu", this.handleHdCtx, this);
50512 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
50513 this.dd = new Roo.grid.GridDragZone(this.grid, {
50514 ddGroup : this.grid.ddGroup || 'GridDD'
50519 for(var i = 0; i < colCount; i++){
50520 if(cm.isHidden(i)){
50521 this.hideColumn(i);
50523 if(cm.config[i].align){
50524 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
50525 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
50529 this.updateHeaderSortState();
50531 this.beforeInitialResize();
50534 // two part rendering gives faster view to the user
50535 this.renderPhase2.defer(1, this);
50538 renderPhase2 : function(){
50539 // render the rows now
50541 if(this.grid.autoSizeColumns){
50542 this.autoSizeColumns();
50546 beforeInitialResize : function(){
50550 onColumnSplitterMoved : function(i, w){
50551 this.userResized = true;
50552 var cm = this.grid.colModel;
50553 cm.setColumnWidth(i, w, true);
50554 var cid = cm.getColumnId(i);
50555 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
50556 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
50557 this.updateSplitters();
50559 this.grid.fireEvent("columnresize", i, w);
50562 syncRowHeights : function(startIndex, endIndex){
50563 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
50564 startIndex = startIndex || 0;
50565 var mrows = this.getBodyTable().rows;
50566 var lrows = this.getLockedTable().rows;
50567 var len = mrows.length-1;
50568 endIndex = Math.min(endIndex || len, len);
50569 for(var i = startIndex; i <= endIndex; i++){
50570 var m = mrows[i], l = lrows[i];
50571 var h = Math.max(m.offsetHeight, l.offsetHeight);
50572 m.style.height = l.style.height = h + "px";
50577 layout : function(initialRender, is2ndPass){
50579 var auto = g.autoHeight;
50580 var scrollOffset = 16;
50581 var c = g.getGridEl(), cm = this.cm,
50582 expandCol = g.autoExpandColumn,
50584 //c.beginMeasure();
50586 if(!c.dom.offsetWidth){ // display:none?
50588 this.lockedWrap.show();
50589 this.mainWrap.show();
50594 var hasLock = this.cm.isLocked(0);
50596 var tbh = this.headerPanel.getHeight();
50597 var bbh = this.footerPanel.getHeight();
50600 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
50601 var newHeight = ch + c.getBorderWidth("tb");
50603 newHeight = Math.min(g.maxHeight, newHeight);
50605 c.setHeight(newHeight);
50609 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
50612 var s = this.scroller;
50614 var csize = c.getSize(true);
50616 this.el.setSize(csize.width, csize.height);
50618 this.headerPanel.setWidth(csize.width);
50619 this.footerPanel.setWidth(csize.width);
50621 var hdHeight = this.mainHd.getHeight();
50622 var vw = csize.width;
50623 var vh = csize.height - (tbh + bbh);
50627 var bt = this.getBodyTable();
50628 var ltWidth = hasLock ?
50629 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
50631 var scrollHeight = bt.offsetHeight;
50632 var scrollWidth = ltWidth + bt.offsetWidth;
50633 var vscroll = false, hscroll = false;
50635 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
50637 var lw = this.lockedWrap, mw = this.mainWrap;
50638 var lb = this.lockedBody, mb = this.mainBody;
50640 setTimeout(function(){
50641 var t = s.dom.offsetTop;
50642 var w = s.dom.clientWidth,
50643 h = s.dom.clientHeight;
50646 lw.setSize(ltWidth, h);
50648 mw.setLeftTop(ltWidth, t);
50649 mw.setSize(w-ltWidth, h);
50651 lb.setHeight(h-hdHeight);
50652 mb.setHeight(h-hdHeight);
50654 if(is2ndPass !== true && !gv.userResized && expandCol){
50655 // high speed resize without full column calculation
50657 var ci = cm.getIndexById(expandCol);
50659 ci = cm.findColumnIndex(expandCol);
50661 ci = Math.max(0, ci); // make sure it's got at least the first col.
50662 var expandId = cm.getColumnId(ci);
50663 var tw = cm.getTotalWidth(false);
50664 var currentWidth = cm.getColumnWidth(ci);
50665 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
50666 if(currentWidth != cw){
50667 cm.setColumnWidth(ci, cw, true);
50668 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
50669 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
50670 gv.updateSplitters();
50671 gv.layout(false, true);
50683 onWindowResize : function(){
50684 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
50690 appendFooter : function(parentEl){
50694 sortAscText : "Sort Ascending",
50695 sortDescText : "Sort Descending",
50696 lockText : "Lock Column",
50697 unlockText : "Unlock Column",
50698 columnsText : "Columns"
50702 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
50703 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
50704 this.proxy.el.addClass('x-grid3-col-dd');
50707 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
50708 handleMouseDown : function(e){
50712 callHandleMouseDown : function(e){
50713 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
50718 * Ext JS Library 1.1.1
50719 * Copyright(c) 2006-2007, Ext JS, LLC.
50721 * Originally Released Under LGPL - original licence link has changed is not relivant.
50724 * <script type="text/javascript">
50728 // This is a support class used internally by the Grid components
50729 Roo.grid.SplitDragZone = function(grid, hd, hd2){
50731 this.view = grid.getView();
50732 this.proxy = this.view.resizeProxy;
50733 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
50734 "gridSplitters" + this.grid.getGridEl().id, {
50735 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
50737 this.setHandleElId(Roo.id(hd));
50738 this.setOuterHandleElId(Roo.id(hd2));
50739 this.scroll = false;
50741 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
50742 fly: Roo.Element.fly,
50744 b4StartDrag : function(x, y){
50745 this.view.headersDisabled = true;
50746 this.proxy.setHeight(this.view.mainWrap.getHeight());
50747 var w = this.cm.getColumnWidth(this.cellIndex);
50748 var minw = Math.max(w-this.grid.minColumnWidth, 0);
50749 this.resetConstraints();
50750 this.setXConstraint(minw, 1000);
50751 this.setYConstraint(0, 0);
50752 this.minX = x - minw;
50753 this.maxX = x + 1000;
50755 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
50759 handleMouseDown : function(e){
50760 ev = Roo.EventObject.setEvent(e);
50761 var t = this.fly(ev.getTarget());
50762 if(t.hasClass("x-grid-split")){
50763 this.cellIndex = this.view.getCellIndex(t.dom);
50764 this.split = t.dom;
50765 this.cm = this.grid.colModel;
50766 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
50767 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
50772 endDrag : function(e){
50773 this.view.headersDisabled = false;
50774 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
50775 var diff = endX - this.startPos;
50776 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
50779 autoOffset : function(){
50780 this.setDelta(0,0);
50784 * Ext JS Library 1.1.1
50785 * Copyright(c) 2006-2007, Ext JS, LLC.
50787 * Originally Released Under LGPL - original licence link has changed is not relivant.
50790 * <script type="text/javascript">
50794 // This is a support class used internally by the Grid components
50795 Roo.grid.GridDragZone = function(grid, config){
50796 this.view = grid.getView();
50797 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
50798 if(this.view.lockedBody){
50799 this.setHandleElId(Roo.id(this.view.mainBody.dom));
50800 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
50802 this.scroll = false;
50804 this.ddel = document.createElement('div');
50805 this.ddel.className = 'x-grid-dd-wrap';
50808 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
50809 ddGroup : "GridDD",
50811 getDragData : function(e){
50812 var t = Roo.lib.Event.getTarget(e);
50813 var rowIndex = this.view.findRowIndex(t);
50814 if(rowIndex !== false){
50815 var sm = this.grid.selModel;
50816 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
50817 // sm.mouseDown(e, t);
50819 if (e.hasModifier()){
50820 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
50822 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
50827 onInitDrag : function(e){
50828 var data = this.dragData;
50829 this.ddel.innerHTML = this.grid.getDragDropText();
50830 this.proxy.update(this.ddel);
50831 // fire start drag?
50834 afterRepair : function(){
50835 this.dragging = false;
50838 getRepairXY : function(e, data){
50842 onEndDrag : function(data, e){
50846 onValidDrop : function(dd, e, id){
50851 beforeInvalidDrop : function(e, id){
50856 * Ext JS Library 1.1.1
50857 * Copyright(c) 2006-2007, Ext JS, LLC.
50859 * Originally Released Under LGPL - original licence link has changed is not relivant.
50862 * <script type="text/javascript">
50867 * @class Roo.grid.ColumnModel
50868 * @extends Roo.util.Observable
50869 * This is the default implementation of a ColumnModel used by the Grid. It defines
50870 * the columns in the grid.
50873 var colModel = new Roo.grid.ColumnModel([
50874 {header: "Ticker", width: 60, sortable: true, locked: true},
50875 {header: "Company Name", width: 150, sortable: true},
50876 {header: "Market Cap.", width: 100, sortable: true},
50877 {header: "$ Sales", width: 100, sortable: true, renderer: money},
50878 {header: "Employees", width: 100, sortable: true, resizable: false}
50883 * The config options listed for this class are options which may appear in each
50884 * individual column definition.
50885 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
50887 * @param {Object} config An Array of column config objects. See this class's
50888 * config objects for details.
50890 Roo.grid.ColumnModel = function(config){
50892 * The config passed into the constructor
50894 this.config = config;
50897 // if no id, create one
50898 // if the column does not have a dataIndex mapping,
50899 // map it to the order it is in the config
50900 for(var i = 0, len = config.length; i < len; i++){
50902 if(typeof c.dataIndex == "undefined"){
50905 if(typeof c.renderer == "string"){
50906 c.renderer = Roo.util.Format[c.renderer];
50908 if(typeof c.id == "undefined"){
50911 if(c.editor && c.editor.xtype){
50912 c.editor = Roo.factory(c.editor, Roo.grid);
50914 if(c.editor && c.editor.isFormField){
50915 c.editor = new Roo.grid.GridEditor(c.editor);
50917 this.lookup[c.id] = c;
50921 * The width of columns which have no width specified (defaults to 100)
50924 this.defaultWidth = 100;
50927 * Default sortable of columns which have no sortable specified (defaults to false)
50930 this.defaultSortable = false;
50934 * @event widthchange
50935 * Fires when the width of a column changes.
50936 * @param {ColumnModel} this
50937 * @param {Number} columnIndex The column index
50938 * @param {Number} newWidth The new width
50940 "widthchange": true,
50942 * @event headerchange
50943 * Fires when the text of a header changes.
50944 * @param {ColumnModel} this
50945 * @param {Number} columnIndex The column index
50946 * @param {Number} newText The new header text
50948 "headerchange": true,
50950 * @event hiddenchange
50951 * Fires when a column is hidden or "unhidden".
50952 * @param {ColumnModel} this
50953 * @param {Number} columnIndex The column index
50954 * @param {Boolean} hidden true if hidden, false otherwise
50956 "hiddenchange": true,
50958 * @event columnmoved
50959 * Fires when a column is moved.
50960 * @param {ColumnModel} this
50961 * @param {Number} oldIndex
50962 * @param {Number} newIndex
50964 "columnmoved" : true,
50966 * @event columlockchange
50967 * Fires when a column's locked state is changed
50968 * @param {ColumnModel} this
50969 * @param {Number} colIndex
50970 * @param {Boolean} locked true if locked
50972 "columnlockchange" : true
50974 Roo.grid.ColumnModel.superclass.constructor.call(this);
50976 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
50978 * @cfg {String} header The header text to display in the Grid view.
50981 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
50982 * {@link Roo.data.Record} definition from which to draw the column's value. If not
50983 * specified, the column's index is used as an index into the Record's data Array.
50986 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
50987 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
50990 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
50991 * Defaults to the value of the {@link #defaultSortable} property.
50992 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
50995 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
50998 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
51001 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
51004 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
51007 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
51008 * given the cell's data value. See {@link #setRenderer}. If not specified, the
51009 * default renderer uses the raw data value.
51012 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
51015 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
51019 * Returns the id of the column at the specified index.
51020 * @param {Number} index The column index
51021 * @return {String} the id
51023 getColumnId : function(index){
51024 return this.config[index].id;
51028 * Returns the column for a specified id.
51029 * @param {String} id The column id
51030 * @return {Object} the column
51032 getColumnById : function(id){
51033 return this.lookup[id];
51038 * Returns the column for a specified dataIndex.
51039 * @param {String} dataIndex The column dataIndex
51040 * @return {Object|Boolean} the column or false if not found
51042 getColumnByDataIndex: function(dataIndex){
51043 var index = this.findColumnIndex(dataIndex);
51044 return index > -1 ? this.config[index] : false;
51048 * Returns the index for a specified column id.
51049 * @param {String} id The column id
51050 * @return {Number} the index, or -1 if not found
51052 getIndexById : function(id){
51053 for(var i = 0, len = this.config.length; i < len; i++){
51054 if(this.config[i].id == id){
51062 * Returns the index for a specified column dataIndex.
51063 * @param {String} dataIndex The column dataIndex
51064 * @return {Number} the index, or -1 if not found
51067 findColumnIndex : function(dataIndex){
51068 for(var i = 0, len = this.config.length; i < len; i++){
51069 if(this.config[i].dataIndex == dataIndex){
51077 moveColumn : function(oldIndex, newIndex){
51078 var c = this.config[oldIndex];
51079 this.config.splice(oldIndex, 1);
51080 this.config.splice(newIndex, 0, c);
51081 this.dataMap = null;
51082 this.fireEvent("columnmoved", this, oldIndex, newIndex);
51085 isLocked : function(colIndex){
51086 return this.config[colIndex].locked === true;
51089 setLocked : function(colIndex, value, suppressEvent){
51090 if(this.isLocked(colIndex) == value){
51093 this.config[colIndex].locked = value;
51094 if(!suppressEvent){
51095 this.fireEvent("columnlockchange", this, colIndex, value);
51099 getTotalLockedWidth : function(){
51100 var totalWidth = 0;
51101 for(var i = 0; i < this.config.length; i++){
51102 if(this.isLocked(i) && !this.isHidden(i)){
51103 this.totalWidth += this.getColumnWidth(i);
51109 getLockedCount : function(){
51110 for(var i = 0, len = this.config.length; i < len; i++){
51111 if(!this.isLocked(i)){
51118 * Returns the number of columns.
51121 getColumnCount : function(visibleOnly){
51122 if(visibleOnly === true){
51124 for(var i = 0, len = this.config.length; i < len; i++){
51125 if(!this.isHidden(i)){
51131 return this.config.length;
51135 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
51136 * @param {Function} fn
51137 * @param {Object} scope (optional)
51138 * @return {Array} result
51140 getColumnsBy : function(fn, scope){
51142 for(var i = 0, len = this.config.length; i < len; i++){
51143 var c = this.config[i];
51144 if(fn.call(scope||this, c, i) === true){
51152 * Returns true if the specified column is sortable.
51153 * @param {Number} col The column index
51154 * @return {Boolean}
51156 isSortable : function(col){
51157 if(typeof this.config[col].sortable == "undefined"){
51158 return this.defaultSortable;
51160 return this.config[col].sortable;
51164 * Returns the rendering (formatting) function defined for the column.
51165 * @param {Number} col The column index.
51166 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
51168 getRenderer : function(col){
51169 if(!this.config[col].renderer){
51170 return Roo.grid.ColumnModel.defaultRenderer;
51172 return this.config[col].renderer;
51176 * Sets the rendering (formatting) function for a column.
51177 * @param {Number} col The column index
51178 * @param {Function} fn The function to use to process the cell's raw data
51179 * to return HTML markup for the grid view. The render function is called with
51180 * the following parameters:<ul>
51181 * <li>Data value.</li>
51182 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
51183 * <li>css A CSS style string to apply to the table cell.</li>
51184 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
51185 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
51186 * <li>Row index</li>
51187 * <li>Column index</li>
51188 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
51190 setRenderer : function(col, fn){
51191 this.config[col].renderer = fn;
51195 * Returns the width for the specified column.
51196 * @param {Number} col The column index
51199 getColumnWidth : function(col){
51200 return this.config[col].width * 1 || this.defaultWidth;
51204 * Sets the width for a column.
51205 * @param {Number} col The column index
51206 * @param {Number} width The new width
51208 setColumnWidth : function(col, width, suppressEvent){
51209 this.config[col].width = width;
51210 this.totalWidth = null;
51211 if(!suppressEvent){
51212 this.fireEvent("widthchange", this, col, width);
51217 * Returns the total width of all columns.
51218 * @param {Boolean} includeHidden True to include hidden column widths
51221 getTotalWidth : function(includeHidden){
51222 if(!this.totalWidth){
51223 this.totalWidth = 0;
51224 for(var i = 0, len = this.config.length; i < len; i++){
51225 if(includeHidden || !this.isHidden(i)){
51226 this.totalWidth += this.getColumnWidth(i);
51230 return this.totalWidth;
51234 * Returns the header for the specified column.
51235 * @param {Number} col The column index
51238 getColumnHeader : function(col){
51239 return this.config[col].header;
51243 * Sets the header for a column.
51244 * @param {Number} col The column index
51245 * @param {String} header The new header
51247 setColumnHeader : function(col, header){
51248 this.config[col].header = header;
51249 this.fireEvent("headerchange", this, col, header);
51253 * Returns the tooltip for the specified column.
51254 * @param {Number} col The column index
51257 getColumnTooltip : function(col){
51258 return this.config[col].tooltip;
51261 * Sets the tooltip for a column.
51262 * @param {Number} col The column index
51263 * @param {String} tooltip The new tooltip
51265 setColumnTooltip : function(col, tooltip){
51266 this.config[col].tooltip = tooltip;
51270 * Returns the dataIndex for the specified column.
51271 * @param {Number} col The column index
51274 getDataIndex : function(col){
51275 return this.config[col].dataIndex;
51279 * Sets the dataIndex for a column.
51280 * @param {Number} col The column index
51281 * @param {Number} dataIndex The new dataIndex
51283 setDataIndex : function(col, dataIndex){
51284 this.config[col].dataIndex = dataIndex;
51290 * Returns true if the cell is editable.
51291 * @param {Number} colIndex The column index
51292 * @param {Number} rowIndex The row index
51293 * @return {Boolean}
51295 isCellEditable : function(colIndex, rowIndex){
51296 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
51300 * Returns the editor defined for the cell/column.
51301 * return false or null to disable editing.
51302 * @param {Number} colIndex The column index
51303 * @param {Number} rowIndex The row index
51306 getCellEditor : function(colIndex, rowIndex){
51307 return this.config[colIndex].editor;
51311 * Sets if a column is editable.
51312 * @param {Number} col The column index
51313 * @param {Boolean} editable True if the column is editable
51315 setEditable : function(col, editable){
51316 this.config[col].editable = editable;
51321 * Returns true if the column is hidden.
51322 * @param {Number} colIndex The column index
51323 * @return {Boolean}
51325 isHidden : function(colIndex){
51326 return this.config[colIndex].hidden;
51331 * Returns true if the column width cannot be changed
51333 isFixed : function(colIndex){
51334 return this.config[colIndex].fixed;
51338 * Returns true if the column can be resized
51339 * @return {Boolean}
51341 isResizable : function(colIndex){
51342 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
51345 * Sets if a column is hidden.
51346 * @param {Number} colIndex The column index
51347 * @param {Boolean} hidden True if the column is hidden
51349 setHidden : function(colIndex, hidden){
51350 this.config[colIndex].hidden = hidden;
51351 this.totalWidth = null;
51352 this.fireEvent("hiddenchange", this, colIndex, hidden);
51356 * Sets the editor for a column.
51357 * @param {Number} col The column index
51358 * @param {Object} editor The editor object
51360 setEditor : function(col, editor){
51361 this.config[col].editor = editor;
51365 Roo.grid.ColumnModel.defaultRenderer = function(value){
51366 if(typeof value == "string" && value.length < 1){
51372 // Alias for backwards compatibility
51373 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
51376 * Ext JS Library 1.1.1
51377 * Copyright(c) 2006-2007, Ext JS, LLC.
51379 * Originally Released Under LGPL - original licence link has changed is not relivant.
51382 * <script type="text/javascript">
51386 * @class Roo.grid.AbstractSelectionModel
51387 * @extends Roo.util.Observable
51388 * Abstract base class for grid SelectionModels. It provides the interface that should be
51389 * implemented by descendant classes. This class should not be directly instantiated.
51392 Roo.grid.AbstractSelectionModel = function(){
51393 this.locked = false;
51394 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
51397 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
51398 /** @ignore Called by the grid automatically. Do not call directly. */
51399 init : function(grid){
51405 * Locks the selections.
51408 this.locked = true;
51412 * Unlocks the selections.
51414 unlock : function(){
51415 this.locked = false;
51419 * Returns true if the selections are locked.
51420 * @return {Boolean}
51422 isLocked : function(){
51423 return this.locked;
51427 * Ext JS Library 1.1.1
51428 * Copyright(c) 2006-2007, Ext JS, LLC.
51430 * Originally Released Under LGPL - original licence link has changed is not relivant.
51433 * <script type="text/javascript">
51436 * @extends Roo.grid.AbstractSelectionModel
51437 * @class Roo.grid.RowSelectionModel
51438 * The default SelectionModel used by {@link Roo.grid.Grid}.
51439 * It supports multiple selections and keyboard selection/navigation.
51441 * @param {Object} config
51443 Roo.grid.RowSelectionModel = function(config){
51444 Roo.apply(this, config);
51445 this.selections = new Roo.util.MixedCollection(false, function(o){
51450 this.lastActive = false;
51454 * @event selectionchange
51455 * Fires when the selection changes
51456 * @param {SelectionModel} this
51458 "selectionchange" : true,
51460 * @event afterselectionchange
51461 * Fires after the selection changes (eg. by key press or clicking)
51462 * @param {SelectionModel} this
51464 "afterselectionchange" : true,
51466 * @event beforerowselect
51467 * Fires when a row is selected being selected, return false to cancel.
51468 * @param {SelectionModel} this
51469 * @param {Number} rowIndex The selected index
51470 * @param {Boolean} keepExisting False if other selections will be cleared
51472 "beforerowselect" : true,
51475 * Fires when a row is selected.
51476 * @param {SelectionModel} this
51477 * @param {Number} rowIndex The selected index
51478 * @param {Roo.data.Record} r The record
51480 "rowselect" : true,
51482 * @event rowdeselect
51483 * Fires when a row is deselected.
51484 * @param {SelectionModel} this
51485 * @param {Number} rowIndex The selected index
51487 "rowdeselect" : true
51489 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
51490 this.locked = false;
51493 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
51495 * @cfg {Boolean} singleSelect
51496 * True to allow selection of only one row at a time (defaults to false)
51498 singleSelect : false,
51501 initEvents : function(){
51503 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
51504 this.grid.on("mousedown", this.handleMouseDown, this);
51505 }else{ // allow click to work like normal
51506 this.grid.on("rowclick", this.handleDragableRowClick, this);
51509 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
51510 "up" : function(e){
51512 this.selectPrevious(e.shiftKey);
51513 }else if(this.last !== false && this.lastActive !== false){
51514 var last = this.last;
51515 this.selectRange(this.last, this.lastActive-1);
51516 this.grid.getView().focusRow(this.lastActive);
51517 if(last !== false){
51521 this.selectFirstRow();
51523 this.fireEvent("afterselectionchange", this);
51525 "down" : function(e){
51527 this.selectNext(e.shiftKey);
51528 }else if(this.last !== false && this.lastActive !== false){
51529 var last = this.last;
51530 this.selectRange(this.last, this.lastActive+1);
51531 this.grid.getView().focusRow(this.lastActive);
51532 if(last !== false){
51536 this.selectFirstRow();
51538 this.fireEvent("afterselectionchange", this);
51543 var view = this.grid.view;
51544 view.on("refresh", this.onRefresh, this);
51545 view.on("rowupdated", this.onRowUpdated, this);
51546 view.on("rowremoved", this.onRemove, this);
51550 onRefresh : function(){
51551 var ds = this.grid.dataSource, i, v = this.grid.view;
51552 var s = this.selections;
51553 s.each(function(r){
51554 if((i = ds.indexOfId(r.id)) != -1){
51563 onRemove : function(v, index, r){
51564 this.selections.remove(r);
51568 onRowUpdated : function(v, index, r){
51569 if(this.isSelected(r)){
51570 v.onRowSelect(index);
51576 * @param {Array} records The records to select
51577 * @param {Boolean} keepExisting (optional) True to keep existing selections
51579 selectRecords : function(records, keepExisting){
51581 this.clearSelections();
51583 var ds = this.grid.dataSource;
51584 for(var i = 0, len = records.length; i < len; i++){
51585 this.selectRow(ds.indexOf(records[i]), true);
51590 * Gets the number of selected rows.
51593 getCount : function(){
51594 return this.selections.length;
51598 * Selects the first row in the grid.
51600 selectFirstRow : function(){
51605 * Select the last row.
51606 * @param {Boolean} keepExisting (optional) True to keep existing selections
51608 selectLastRow : function(keepExisting){
51609 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
51613 * Selects the row immediately following the last selected row.
51614 * @param {Boolean} keepExisting (optional) True to keep existing selections
51616 selectNext : function(keepExisting){
51617 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
51618 this.selectRow(this.last+1, keepExisting);
51619 this.grid.getView().focusRow(this.last);
51624 * Selects the row that precedes the last selected row.
51625 * @param {Boolean} keepExisting (optional) True to keep existing selections
51627 selectPrevious : function(keepExisting){
51629 this.selectRow(this.last-1, keepExisting);
51630 this.grid.getView().focusRow(this.last);
51635 * Returns the selected records
51636 * @return {Array} Array of selected records
51638 getSelections : function(){
51639 return [].concat(this.selections.items);
51643 * Returns the first selected record.
51646 getSelected : function(){
51647 return this.selections.itemAt(0);
51652 * Clears all selections.
51654 clearSelections : function(fast){
51655 if(this.locked) return;
51657 var ds = this.grid.dataSource;
51658 var s = this.selections;
51659 s.each(function(r){
51660 this.deselectRow(ds.indexOfId(r.id));
51664 this.selections.clear();
51671 * Selects all rows.
51673 selectAll : function(){
51674 if(this.locked) return;
51675 this.selections.clear();
51676 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
51677 this.selectRow(i, true);
51682 * Returns True if there is a selection.
51683 * @return {Boolean}
51685 hasSelection : function(){
51686 return this.selections.length > 0;
51690 * Returns True if the specified row is selected.
51691 * @param {Number/Record} record The record or index of the record to check
51692 * @return {Boolean}
51694 isSelected : function(index){
51695 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
51696 return (r && this.selections.key(r.id) ? true : false);
51700 * Returns True if the specified record id is selected.
51701 * @param {String} id The id of record to check
51702 * @return {Boolean}
51704 isIdSelected : function(id){
51705 return (this.selections.key(id) ? true : false);
51709 handleMouseDown : function(e, t){
51710 var view = this.grid.getView(), rowIndex;
51711 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
51714 if(e.shiftKey && this.last !== false){
51715 var last = this.last;
51716 this.selectRange(last, rowIndex, e.ctrlKey);
51717 this.last = last; // reset the last
51718 view.focusRow(rowIndex);
51720 var isSelected = this.isSelected(rowIndex);
51721 if(e.button !== 0 && isSelected){
51722 view.focusRow(rowIndex);
51723 }else if(e.ctrlKey && isSelected){
51724 this.deselectRow(rowIndex);
51725 }else if(!isSelected){
51726 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
51727 view.focusRow(rowIndex);
51730 this.fireEvent("afterselectionchange", this);
51733 handleDragableRowClick : function(grid, rowIndex, e)
51735 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
51736 this.selectRow(rowIndex, false);
51737 grid.view.focusRow(rowIndex);
51738 this.fireEvent("afterselectionchange", this);
51743 * Selects multiple rows.
51744 * @param {Array} rows Array of the indexes of the row to select
51745 * @param {Boolean} keepExisting (optional) True to keep existing selections
51747 selectRows : function(rows, keepExisting){
51749 this.clearSelections();
51751 for(var i = 0, len = rows.length; i < len; i++){
51752 this.selectRow(rows[i], true);
51757 * Selects a range of rows. All rows in between startRow and endRow are also selected.
51758 * @param {Number} startRow The index of the first row in the range
51759 * @param {Number} endRow The index of the last row in the range
51760 * @param {Boolean} keepExisting (optional) True to retain existing selections
51762 selectRange : function(startRow, endRow, keepExisting){
51763 if(this.locked) return;
51765 this.clearSelections();
51767 if(startRow <= endRow){
51768 for(var i = startRow; i <= endRow; i++){
51769 this.selectRow(i, true);
51772 for(var i = startRow; i >= endRow; i--){
51773 this.selectRow(i, true);
51779 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
51780 * @param {Number} startRow The index of the first row in the range
51781 * @param {Number} endRow The index of the last row in the range
51783 deselectRange : function(startRow, endRow, preventViewNotify){
51784 if(this.locked) return;
51785 for(var i = startRow; i <= endRow; i++){
51786 this.deselectRow(i, preventViewNotify);
51792 * @param {Number} row The index of the row to select
51793 * @param {Boolean} keepExisting (optional) True to keep existing selections
51795 selectRow : function(index, keepExisting, preventViewNotify){
51796 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
51797 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
51798 if(!keepExisting || this.singleSelect){
51799 this.clearSelections();
51801 var r = this.grid.dataSource.getAt(index);
51802 this.selections.add(r);
51803 this.last = this.lastActive = index;
51804 if(!preventViewNotify){
51805 this.grid.getView().onRowSelect(index);
51807 this.fireEvent("rowselect", this, index, r);
51808 this.fireEvent("selectionchange", this);
51814 * @param {Number} row The index of the row to deselect
51816 deselectRow : function(index, preventViewNotify){
51817 if(this.locked) return;
51818 if(this.last == index){
51821 if(this.lastActive == index){
51822 this.lastActive = false;
51824 var r = this.grid.dataSource.getAt(index);
51825 this.selections.remove(r);
51826 if(!preventViewNotify){
51827 this.grid.getView().onRowDeselect(index);
51829 this.fireEvent("rowdeselect", this, index);
51830 this.fireEvent("selectionchange", this);
51834 restoreLast : function(){
51836 this.last = this._last;
51841 acceptsNav : function(row, col, cm){
51842 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51846 onEditorKey : function(field, e){
51847 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
51852 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51854 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51856 }else if(k == e.ENTER && !e.ctrlKey){
51860 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
51862 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
51864 }else if(k == e.ESC){
51868 g.startEditing(newCell[0], newCell[1]);
51873 * Ext JS Library 1.1.1
51874 * Copyright(c) 2006-2007, Ext JS, LLC.
51876 * Originally Released Under LGPL - original licence link has changed is not relivant.
51879 * <script type="text/javascript">
51882 * @class Roo.grid.CellSelectionModel
51883 * @extends Roo.grid.AbstractSelectionModel
51884 * This class provides the basic implementation for cell selection in a grid.
51886 * @param {Object} config The object containing the configuration of this model.
51887 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
51889 Roo.grid.CellSelectionModel = function(config){
51890 Roo.apply(this, config);
51892 this.selection = null;
51896 * @event beforerowselect
51897 * Fires before a cell is selected.
51898 * @param {SelectionModel} this
51899 * @param {Number} rowIndex The selected row index
51900 * @param {Number} colIndex The selected cell index
51902 "beforecellselect" : true,
51904 * @event cellselect
51905 * Fires when a cell is selected.
51906 * @param {SelectionModel} this
51907 * @param {Number} rowIndex The selected row index
51908 * @param {Number} colIndex The selected cell index
51910 "cellselect" : true,
51912 * @event selectionchange
51913 * Fires when the active selection changes.
51914 * @param {SelectionModel} this
51915 * @param {Object} selection null for no selection or an object (o) with two properties
51917 <li>o.record: the record object for the row the selection is in</li>
51918 <li>o.cell: An array of [rowIndex, columnIndex]</li>
51921 "selectionchange" : true,
51924 * Fires when the tab (or enter) was pressed on the last editable cell
51925 * You can use this to trigger add new row.
51926 * @param {SelectionModel} this
51930 * @event beforeeditnext
51931 * Fires before the next editable sell is made active
51932 * You can use this to skip to another cell or fire the tabend
51933 * if you set cell to false
51934 * @param {Object} eventdata object : { cell : [ row, col ] }
51936 "beforeeditnext" : true
51938 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
51941 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
51943 enter_is_tab: false,
51946 initEvents : function(){
51947 this.grid.on("mousedown", this.handleMouseDown, this);
51948 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
51949 var view = this.grid.view;
51950 view.on("refresh", this.onViewChange, this);
51951 view.on("rowupdated", this.onRowUpdated, this);
51952 view.on("beforerowremoved", this.clearSelections, this);
51953 view.on("beforerowsinserted", this.clearSelections, this);
51954 if(this.grid.isEditor){
51955 this.grid.on("beforeedit", this.beforeEdit, this);
51960 beforeEdit : function(e){
51961 this.select(e.row, e.column, false, true, e.record);
51965 onRowUpdated : function(v, index, r){
51966 if(this.selection && this.selection.record == r){
51967 v.onCellSelect(index, this.selection.cell[1]);
51972 onViewChange : function(){
51973 this.clearSelections(true);
51977 * Returns the currently selected cell,.
51978 * @return {Array} The selected cell (row, column) or null if none selected.
51980 getSelectedCell : function(){
51981 return this.selection ? this.selection.cell : null;
51985 * Clears all selections.
51986 * @param {Boolean} true to prevent the gridview from being notified about the change.
51988 clearSelections : function(preventNotify){
51989 var s = this.selection;
51991 if(preventNotify !== true){
51992 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
51994 this.selection = null;
51995 this.fireEvent("selectionchange", this, null);
52000 * Returns true if there is a selection.
52001 * @return {Boolean}
52003 hasSelection : function(){
52004 return this.selection ? true : false;
52008 handleMouseDown : function(e, t){
52009 var v = this.grid.getView();
52010 if(this.isLocked()){
52013 var row = v.findRowIndex(t);
52014 var cell = v.findCellIndex(t);
52015 if(row !== false && cell !== false){
52016 this.select(row, cell);
52022 * @param {Number} rowIndex
52023 * @param {Number} collIndex
52025 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
52026 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
52027 this.clearSelections();
52028 r = r || this.grid.dataSource.getAt(rowIndex);
52031 cell : [rowIndex, colIndex]
52033 if(!preventViewNotify){
52034 var v = this.grid.getView();
52035 v.onCellSelect(rowIndex, colIndex);
52036 if(preventFocus !== true){
52037 v.focusCell(rowIndex, colIndex);
52040 this.fireEvent("cellselect", this, rowIndex, colIndex);
52041 this.fireEvent("selectionchange", this, this.selection);
52046 isSelectable : function(rowIndex, colIndex, cm){
52047 return !cm.isHidden(colIndex);
52051 handleKeyDown : function(e){
52052 //Roo.log('Cell Sel Model handleKeyDown');
52053 if(!e.isNavKeyPress()){
52056 var g = this.grid, s = this.selection;
52059 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
52061 this.select(cell[0], cell[1]);
52066 var walk = function(row, col, step){
52067 return g.walkCells(row, col, step, sm.isSelectable, sm);
52069 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
52076 // handled by onEditorKey
52077 if (g.isEditor && g.editing) {
52081 newCell = walk(r, c-1, -1);
52083 newCell = walk(r, c+1, 1);
52088 newCell = walk(r+1, c, 1);
52092 newCell = walk(r-1, c, -1);
52096 newCell = walk(r, c+1, 1);
52100 newCell = walk(r, c-1, -1);
52105 if(g.isEditor && !g.editing){
52106 g.startEditing(r, c);
52115 this.select(newCell[0], newCell[1]);
52121 acceptsNav : function(row, col, cm){
52122 return !cm.isHidden(col) && cm.isCellEditable(col, row);
52126 * @param {Number} field (not used) - as it's normally used as a listener
52127 * @param {Number} e - event - fake it by using
52129 * var e = Roo.EventObjectImpl.prototype;
52130 * e.keyCode = e.TAB
52134 onEditorKey : function(field, e){
52136 var k = e.getKey(),
52139 ed = g.activeEditor,
52141 ///Roo.log('onEditorKey' + k);
52144 if (this.enter_is_tab && k == e.ENTER) {
52150 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
52152 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
52158 } else if(k == e.ENTER && !e.ctrlKey){
52161 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
52163 } else if(k == e.ESC){
52168 var ecall = { cell : newCell, forward : forward };
52169 this.fireEvent('beforeeditnext', ecall );
52170 newCell = ecall.cell;
52171 forward = ecall.forward;
52175 //Roo.log('next cell after edit');
52176 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
52177 } else if (forward) {
52178 // tabbed past last
52179 this.fireEvent.defer(100, this, ['tabend',this]);
52184 * Ext JS Library 1.1.1
52185 * Copyright(c) 2006-2007, Ext JS, LLC.
52187 * Originally Released Under LGPL - original licence link has changed is not relivant.
52190 * <script type="text/javascript">
52194 * @class Roo.grid.EditorGrid
52195 * @extends Roo.grid.Grid
52196 * Class for creating and editable grid.
52197 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52198 * The container MUST have some type of size defined for the grid to fill. The container will be
52199 * automatically set to position relative if it isn't already.
52200 * @param {Object} dataSource The data model to bind to
52201 * @param {Object} colModel The column model with info about this grid's columns
52203 Roo.grid.EditorGrid = function(container, config){
52204 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
52205 this.getGridEl().addClass("xedit-grid");
52207 if(!this.selModel){
52208 this.selModel = new Roo.grid.CellSelectionModel();
52211 this.activeEditor = null;
52215 * @event beforeedit
52216 * Fires before cell editing is triggered. The edit event object has the following properties <br />
52217 * <ul style="padding:5px;padding-left:16px;">
52218 * <li>grid - This grid</li>
52219 * <li>record - The record being edited</li>
52220 * <li>field - The field name being edited</li>
52221 * <li>value - The value for the field being edited.</li>
52222 * <li>row - The grid row index</li>
52223 * <li>column - The grid column index</li>
52224 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
52226 * @param {Object} e An edit event (see above for description)
52228 "beforeedit" : true,
52231 * Fires after a cell is edited. <br />
52232 * <ul style="padding:5px;padding-left:16px;">
52233 * <li>grid - This grid</li>
52234 * <li>record - The record being edited</li>
52235 * <li>field - The field name being edited</li>
52236 * <li>value - The value being set</li>
52237 * <li>originalValue - The original value for the field, before the edit.</li>
52238 * <li>row - The grid row index</li>
52239 * <li>column - The grid column index</li>
52241 * @param {Object} e An edit event (see above for description)
52243 "afteredit" : true,
52245 * @event validateedit
52246 * Fires after a cell is edited, but before the value is set in the record.
52247 * You can use this to modify the value being set in the field, Return false
52248 * to cancel the change. The edit event object has the following properties <br />
52249 * <ul style="padding:5px;padding-left:16px;">
52250 * <li>editor - This editor</li>
52251 * <li>grid - This grid</li>
52252 * <li>record - The record being edited</li>
52253 * <li>field - The field name being edited</li>
52254 * <li>value - The value being set</li>
52255 * <li>originalValue - The original value for the field, before the edit.</li>
52256 * <li>row - The grid row index</li>
52257 * <li>column - The grid column index</li>
52258 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
52260 * @param {Object} e An edit event (see above for description)
52262 "validateedit" : true
52264 this.on("bodyscroll", this.stopEditing, this);
52265 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
52268 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
52270 * @cfg {Number} clicksToEdit
52271 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
52278 trackMouseOver: false, // causes very odd FF errors
52280 onCellDblClick : function(g, row, col){
52281 this.startEditing(row, col);
52284 onEditComplete : function(ed, value, startValue){
52285 this.editing = false;
52286 this.activeEditor = null;
52287 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
52289 var field = this.colModel.getDataIndex(ed.col);
52294 originalValue: startValue,
52301 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
52304 if(String(value) !== String(startValue)){
52306 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
52307 r.set(field, e.value);
52308 // if we are dealing with a combo box..
52309 // then we also set the 'name' colum to be the displayField
52310 if (ed.field.displayField && ed.field.name) {
52311 r.set(ed.field.name, ed.field.el.dom.value);
52314 delete e.cancel; //?? why!!!
52315 this.fireEvent("afteredit", e);
52318 this.fireEvent("afteredit", e); // always fire it!
52320 this.view.focusCell(ed.row, ed.col);
52324 * Starts editing the specified for the specified row/column
52325 * @param {Number} rowIndex
52326 * @param {Number} colIndex
52328 startEditing : function(row, col){
52329 this.stopEditing();
52330 if(this.colModel.isCellEditable(col, row)){
52331 this.view.ensureVisible(row, col, true);
52333 var r = this.dataSource.getAt(row);
52334 var field = this.colModel.getDataIndex(col);
52335 var cell = Roo.get(this.view.getCell(row,col));
52340 value: r.data[field],
52345 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
52346 this.editing = true;
52347 var ed = this.colModel.getCellEditor(col, row);
52353 ed.render(ed.parentEl || document.body);
52359 (function(){ // complex but required for focus issues in safari, ie and opera
52363 ed.on("complete", this.onEditComplete, this, {single: true});
52364 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
52365 this.activeEditor = ed;
52366 var v = r.data[field];
52367 ed.startEdit(this.view.getCell(row, col), v);
52368 // combo's with 'displayField and name set
52369 if (ed.field.displayField && ed.field.name) {
52370 ed.field.el.dom.value = r.data[ed.field.name];
52374 }).defer(50, this);
52380 * Stops any active editing
52382 stopEditing : function(){
52383 if(this.activeEditor){
52384 this.activeEditor.completeEdit();
52386 this.activeEditor = null;
52390 * Ext JS Library 1.1.1
52391 * Copyright(c) 2006-2007, Ext JS, LLC.
52393 * Originally Released Under LGPL - original licence link has changed is not relivant.
52396 * <script type="text/javascript">
52399 // private - not really -- you end up using it !
52400 // This is a support class used internally by the Grid components
52403 * @class Roo.grid.GridEditor
52404 * @extends Roo.Editor
52405 * Class for creating and editable grid elements.
52406 * @param {Object} config any settings (must include field)
52408 Roo.grid.GridEditor = function(field, config){
52409 if (!config && field.field) {
52411 field = Roo.factory(config.field, Roo.form);
52413 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
52414 field.monitorTab = false;
52417 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
52420 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
52423 alignment: "tl-tl",
52426 cls: "x-small-editor x-grid-editor",
52431 * Ext JS Library 1.1.1
52432 * Copyright(c) 2006-2007, Ext JS, LLC.
52434 * Originally Released Under LGPL - original licence link has changed is not relivant.
52437 * <script type="text/javascript">
52442 Roo.grid.PropertyRecord = Roo.data.Record.create([
52443 {name:'name',type:'string'}, 'value'
52447 Roo.grid.PropertyStore = function(grid, source){
52449 this.store = new Roo.data.Store({
52450 recordType : Roo.grid.PropertyRecord
52452 this.store.on('update', this.onUpdate, this);
52454 this.setSource(source);
52456 Roo.grid.PropertyStore.superclass.constructor.call(this);
52461 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
52462 setSource : function(o){
52464 this.store.removeAll();
52467 if(this.isEditableValue(o[k])){
52468 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
52471 this.store.loadRecords({records: data}, {}, true);
52474 onUpdate : function(ds, record, type){
52475 if(type == Roo.data.Record.EDIT){
52476 var v = record.data['value'];
52477 var oldValue = record.modified['value'];
52478 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
52479 this.source[record.id] = v;
52481 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
52488 getProperty : function(row){
52489 return this.store.getAt(row);
52492 isEditableValue: function(val){
52493 if(val && val instanceof Date){
52495 }else if(typeof val == 'object' || typeof val == 'function'){
52501 setValue : function(prop, value){
52502 this.source[prop] = value;
52503 this.store.getById(prop).set('value', value);
52506 getSource : function(){
52507 return this.source;
52511 Roo.grid.PropertyColumnModel = function(grid, store){
52514 g.PropertyColumnModel.superclass.constructor.call(this, [
52515 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
52516 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
52518 this.store = store;
52519 this.bselect = Roo.DomHelper.append(document.body, {
52520 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
52521 {tag: 'option', value: 'true', html: 'true'},
52522 {tag: 'option', value: 'false', html: 'false'}
52525 Roo.id(this.bselect);
52528 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
52529 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
52530 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
52531 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
52532 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
52534 this.renderCellDelegate = this.renderCell.createDelegate(this);
52535 this.renderPropDelegate = this.renderProp.createDelegate(this);
52538 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
52542 valueText : 'Value',
52544 dateFormat : 'm/j/Y',
52547 renderDate : function(dateVal){
52548 return dateVal.dateFormat(this.dateFormat);
52551 renderBool : function(bVal){
52552 return bVal ? 'true' : 'false';
52555 isCellEditable : function(colIndex, rowIndex){
52556 return colIndex == 1;
52559 getRenderer : function(col){
52561 this.renderCellDelegate : this.renderPropDelegate;
52564 renderProp : function(v){
52565 return this.getPropertyName(v);
52568 renderCell : function(val){
52570 if(val instanceof Date){
52571 rv = this.renderDate(val);
52572 }else if(typeof val == 'boolean'){
52573 rv = this.renderBool(val);
52575 return Roo.util.Format.htmlEncode(rv);
52578 getPropertyName : function(name){
52579 var pn = this.grid.propertyNames;
52580 return pn && pn[name] ? pn[name] : name;
52583 getCellEditor : function(colIndex, rowIndex){
52584 var p = this.store.getProperty(rowIndex);
52585 var n = p.data['name'], val = p.data['value'];
52587 if(typeof(this.grid.customEditors[n]) == 'string'){
52588 return this.editors[this.grid.customEditors[n]];
52590 if(typeof(this.grid.customEditors[n]) != 'undefined'){
52591 return this.grid.customEditors[n];
52593 if(val instanceof Date){
52594 return this.editors['date'];
52595 }else if(typeof val == 'number'){
52596 return this.editors['number'];
52597 }else if(typeof val == 'boolean'){
52598 return this.editors['boolean'];
52600 return this.editors['string'];
52606 * @class Roo.grid.PropertyGrid
52607 * @extends Roo.grid.EditorGrid
52608 * This class represents the interface of a component based property grid control.
52609 * <br><br>Usage:<pre><code>
52610 var grid = new Roo.grid.PropertyGrid("my-container-id", {
52618 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52619 * The container MUST have some type of size defined for the grid to fill. The container will be
52620 * automatically set to position relative if it isn't already.
52621 * @param {Object} config A config object that sets properties on this grid.
52623 Roo.grid.PropertyGrid = function(container, config){
52624 config = config || {};
52625 var store = new Roo.grid.PropertyStore(this);
52626 this.store = store;
52627 var cm = new Roo.grid.PropertyColumnModel(this, store);
52628 store.store.sort('name', 'ASC');
52629 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
52632 enableColLock:false,
52633 enableColumnMove:false,
52635 trackMouseOver: false,
52638 this.getGridEl().addClass('x-props-grid');
52639 this.lastEditRow = null;
52640 this.on('columnresize', this.onColumnResize, this);
52643 * @event beforepropertychange
52644 * Fires before a property changes (return false to stop?)
52645 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
52646 * @param {String} id Record Id
52647 * @param {String} newval New Value
52648 * @param {String} oldval Old Value
52650 "beforepropertychange": true,
52652 * @event propertychange
52653 * Fires after a property changes
52654 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
52655 * @param {String} id Record Id
52656 * @param {String} newval New Value
52657 * @param {String} oldval Old Value
52659 "propertychange": true
52661 this.customEditors = this.customEditors || {};
52663 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
52666 * @cfg {Object} customEditors map of colnames=> custom editors.
52667 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
52668 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
52669 * false disables editing of the field.
52673 * @cfg {Object} propertyNames map of property Names to their displayed value
52676 render : function(){
52677 Roo.grid.PropertyGrid.superclass.render.call(this);
52678 this.autoSize.defer(100, this);
52681 autoSize : function(){
52682 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
52684 this.view.fitColumns();
52688 onColumnResize : function(){
52689 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
52693 * Sets the data for the Grid
52694 * accepts a Key => Value object of all the elements avaiable.
52695 * @param {Object} data to appear in grid.
52697 setSource : function(source){
52698 this.store.setSource(source);
52702 * Gets all the data from the grid.
52703 * @return {Object} data data stored in grid
52705 getSource : function(){
52706 return this.store.getSource();
52710 * Ext JS Library 1.1.1
52711 * Copyright(c) 2006-2007, Ext JS, LLC.
52713 * Originally Released Under LGPL - original licence link has changed is not relivant.
52716 * <script type="text/javascript">
52720 * @class Roo.LoadMask
52721 * A simple utility class for generically masking elements while loading data. If the element being masked has
52722 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
52723 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
52724 * element's UpdateManager load indicator and will be destroyed after the initial load.
52726 * Create a new LoadMask
52727 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
52728 * @param {Object} config The config object
52730 Roo.LoadMask = function(el, config){
52731 this.el = Roo.get(el);
52732 Roo.apply(this, config);
52734 this.store.on('beforeload', this.onBeforeLoad, this);
52735 this.store.on('load', this.onLoad, this);
52736 this.store.on('loadexception', this.onLoadException, this);
52737 this.removeMask = false;
52739 var um = this.el.getUpdateManager();
52740 um.showLoadIndicator = false; // disable the default indicator
52741 um.on('beforeupdate', this.onBeforeLoad, this);
52742 um.on('update', this.onLoad, this);
52743 um.on('failure', this.onLoad, this);
52744 this.removeMask = true;
52748 Roo.LoadMask.prototype = {
52750 * @cfg {Boolean} removeMask
52751 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
52752 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
52755 * @cfg {String} msg
52756 * The text to display in a centered loading message box (defaults to 'Loading...')
52758 msg : 'Loading...',
52760 * @cfg {String} msgCls
52761 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
52763 msgCls : 'x-mask-loading',
52766 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
52772 * Disables the mask to prevent it from being displayed
52774 disable : function(){
52775 this.disabled = true;
52779 * Enables the mask so that it can be displayed
52781 enable : function(){
52782 this.disabled = false;
52785 onLoadException : function()
52787 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52788 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52790 this.el.unmask(this.removeMask);
52793 onLoad : function()
52795 this.el.unmask(this.removeMask);
52799 onBeforeLoad : function(){
52800 if(!this.disabled){
52801 this.el.mask(this.msg, this.msgCls);
52806 destroy : function(){
52808 this.store.un('beforeload', this.onBeforeLoad, this);
52809 this.store.un('load', this.onLoad, this);
52810 this.store.un('loadexception', this.onLoadException, this);
52812 var um = this.el.getUpdateManager();
52813 um.un('beforeupdate', this.onBeforeLoad, this);
52814 um.un('update', this.onLoad, this);
52815 um.un('failure', this.onLoad, this);
52820 * Ext JS Library 1.1.1
52821 * Copyright(c) 2006-2007, Ext JS, LLC.
52823 * Originally Released Under LGPL - original licence link has changed is not relivant.
52826 * <script type="text/javascript">
52831 * @class Roo.XTemplate
52832 * @extends Roo.Template
52833 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
52835 var t = new Roo.XTemplate(
52836 '<select name="{name}">',
52837 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
52841 // then append, applying the master template values
52844 * Supported features:
52849 {a_variable} - output encoded.
52850 {a_variable.format:("Y-m-d")} - call a method on the variable
52851 {a_variable:raw} - unencoded output
52852 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
52853 {a_variable:this.method_on_template(...)} - call a method on the template object.
52858 <tpl for="a_variable or condition.."></tpl>
52859 <tpl if="a_variable or condition"></tpl>
52860 <tpl exec="some javascript"></tpl>
52861 <tpl name="named_template"></tpl> (experimental)
52863 <tpl for="."></tpl> - just iterate the property..
52864 <tpl for=".."></tpl> - iterates with the parent (probably the template)
52868 Roo.XTemplate = function()
52870 Roo.XTemplate.superclass.constructor.apply(this, arguments);
52877 Roo.extend(Roo.XTemplate, Roo.Template, {
52880 * The various sub templates
52885 * basic tag replacing syntax
52888 * // you can fake an object call by doing this
52892 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
52895 * compile the template
52897 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
52900 compile: function()
52904 s = ['<tpl>', s, '</tpl>'].join('');
52906 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
52907 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
52908 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
52909 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
52910 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
52915 while(true == !!(m = s.match(re))){
52916 var forMatch = m[0].match(nameRe),
52917 ifMatch = m[0].match(ifRe),
52918 execMatch = m[0].match(execRe),
52919 namedMatch = m[0].match(namedRe),
52924 name = forMatch && forMatch[1] ? forMatch[1] : '';
52927 // if - puts fn into test..
52928 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
52930 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
52935 // exec - calls a function... returns empty if true is returned.
52936 exp = execMatch && execMatch[1] ? execMatch[1] : null;
52938 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
52946 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
52947 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
52948 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
52951 var uid = namedMatch ? namedMatch[1] : id;
52955 id: namedMatch ? namedMatch[1] : id,
52962 s = s.replace(m[0], '');
52964 s = s.replace(m[0], '{xtpl'+ id + '}');
52969 for(var i = tpls.length-1; i >= 0; --i){
52970 this.compileTpl(tpls[i]);
52971 this.tpls[tpls[i].id] = tpls[i];
52973 this.master = tpls[tpls.length-1];
52977 * same as applyTemplate, except it's done to one of the subTemplates
52978 * when using named templates, you can do:
52980 * var str = pl.applySubTemplate('your-name', values);
52983 * @param {Number} id of the template
52984 * @param {Object} values to apply to template
52985 * @param {Object} parent (normaly the instance of this object)
52987 applySubTemplate : function(id, values, parent)
52991 var t = this.tpls[id];
52995 if(t.test && !t.test.call(this, values, parent)){
52999 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
53000 Roo.log(e.toString());
53006 if(t.exec && t.exec.call(this, values, parent)){
53010 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
53011 Roo.log(e.toString());
53016 var vs = t.target ? t.target.call(this, values, parent) : values;
53017 parent = t.target ? values : parent;
53018 if(t.target && vs instanceof Array){
53020 for(var i = 0, len = vs.length; i < len; i++){
53021 buf[buf.length] = t.compiled.call(this, vs[i], parent);
53023 return buf.join('');
53025 return t.compiled.call(this, vs, parent);
53027 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
53028 Roo.log(e.toString());
53029 Roo.log(t.compiled);
53034 compileTpl : function(tpl)
53036 var fm = Roo.util.Format;
53037 var useF = this.disableFormats !== true;
53038 var sep = Roo.isGecko ? "+" : ",";
53039 var undef = function(str) {
53040 Roo.log("Property not found :" + str);
53044 var fn = function(m, name, format, args)
53046 //Roo.log(arguments);
53047 args = args ? args.replace(/\\'/g,"'") : args;
53048 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
53049 if (typeof(format) == 'undefined') {
53050 format= 'htmlEncode';
53052 if (format == 'raw' ) {
53056 if(name.substr(0, 4) == 'xtpl'){
53057 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
53060 // build an array of options to determine if value is undefined..
53062 // basically get 'xxxx.yyyy' then do
53063 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
53064 // (function () { Roo.log("Property not found"); return ''; })() :
53069 Roo.each(name.split('.'), function(st) {
53070 lookfor += (lookfor.length ? '.': '') + st;
53071 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
53074 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
53077 if(format && useF){
53079 args = args ? ',' + args : "";
53081 if(format.substr(0, 5) != "this."){
53082 format = "fm." + format + '(';
53084 format = 'this.call("'+ format.substr(5) + '", ';
53088 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
53092 // called with xxyx.yuu:(test,test)
53094 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
53096 // raw.. - :raw modifier..
53097 return "'"+ sep + udef_st + name + ")"+sep+"'";
53101 // branched to use + in gecko and [].join() in others
53103 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
53104 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
53107 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
53108 body.push(tpl.body.replace(/(\r\n|\n)/g,
53109 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
53110 body.push("'].join('');};};");
53111 body = body.join('');
53114 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
53116 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
53122 applyTemplate : function(values){
53123 return this.master.compiled.call(this, values, {});
53124 //var s = this.subs;
53127 apply : function(){
53128 return this.applyTemplate.apply(this, arguments);
53133 Roo.XTemplate.from = function(el){
53134 el = Roo.getDom(el);
53135 return new Roo.XTemplate(el.value || el.innerHTML);
53137 * Original code for Roojs - LGPL
53138 * <script type="text/javascript">
53142 * @class Roo.XComponent
53143 * A delayed Element creator...
53144 * Or a way to group chunks of interface together.
53146 * Mypart.xyx = new Roo.XComponent({
53148 parent : 'Mypart.xyz', // empty == document.element.!!
53152 disabled : function() {}
53154 tree : function() { // return an tree of xtype declared components
53158 xtype : 'NestedLayoutPanel',
53165 * It can be used to build a big heiracy, with parent etc.
53166 * or you can just use this to render a single compoent to a dom element
53167 * MYPART.render(Roo.Element | String(id) | dom_element )
53169 * @extends Roo.util.Observable
53171 * @param cfg {Object} configuration of component
53174 Roo.XComponent = function(cfg) {
53175 Roo.apply(this, cfg);
53179 * Fires when this the componnt is built
53180 * @param {Roo.XComponent} c the component
53185 this.region = this.region || 'center'; // default..
53186 Roo.XComponent.register(this);
53187 this.modules = false;
53188 this.el = false; // where the layout goes..
53192 Roo.extend(Roo.XComponent, Roo.util.Observable, {
53195 * The created element (with Roo.factory())
53196 * @type {Roo.Layout}
53202 * for BC - use el in new code
53203 * @type {Roo.Layout}
53209 * for BC - use el in new code
53210 * @type {Roo.Layout}
53215 * @cfg {Function|boolean} disabled
53216 * If this module is disabled by some rule, return true from the funtion
53221 * @cfg {String} parent
53222 * Name of parent element which it get xtype added to..
53227 * @cfg {String} order
53228 * Used to set the order in which elements are created (usefull for multiple tabs)
53233 * @cfg {String} name
53234 * String to display while loading.
53238 * @cfg {String} region
53239 * Region to render component to (defaults to center)
53244 * @cfg {Array} items
53245 * A single item array - the first element is the root of the tree..
53246 * It's done this way to stay compatible with the Xtype system...
53252 * The method that retuns the tree of parts that make up this compoennt
53259 * render element to dom or tree
53260 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
53263 render : function(el)
53267 var hp = this.parent ? 1 : 0;
53269 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
53270 // if parent is a '#.....' string, then let's use that..
53271 var ename = this.parent.substr(1)
53272 this.parent = false;
53273 el = Roo.get(ename);
53275 Roo.log("Warning - element can not be found :#" + ename );
53281 if (!this.parent) {
53283 el = el ? Roo.get(el) : false;
53285 // it's a top level one..
53287 el : new Roo.BorderLayout(el || document.body, {
53293 tabPosition: 'top',
53294 //resizeTabs: true,
53295 alwaysShowTabs: el && hp? false : true,
53296 hideTabs: el || !hp ? true : false,
53303 if (!this.parent.el) {
53304 // probably an old style ctor, which has been disabled.
53308 // The 'tree' method is '_tree now'
53310 var tree = this._tree ? this._tree() : this.tree();
53311 tree.region = tree.region || this.region;
53312 this.el = this.parent.el.addxtype(tree);
53313 this.fireEvent('built', this);
53315 this.panel = this.el;
53316 this.layout = this.panel.layout;
53317 this.parentLayout = this.parent.layout || false;
53323 Roo.apply(Roo.XComponent, {
53325 * @property hideProgress
53326 * true to disable the building progress bar.. usefull on single page renders.
53329 hideProgress : false,
53331 * @property buildCompleted
53332 * True when the builder has completed building the interface.
53335 buildCompleted : false,
53338 * @property topModule
53339 * the upper most module - uses document.element as it's constructor.
53346 * @property modules
53347 * array of modules to be created by registration system.
53348 * @type {Array} of Roo.XComponent
53353 * @property elmodules
53354 * array of modules to be created by which use #ID
53355 * @type {Array} of Roo.XComponent
53362 * Register components to be built later.
53364 * This solves the following issues
53365 * - Building is not done on page load, but after an authentication process has occured.
53366 * - Interface elements are registered on page load
53367 * - Parent Interface elements may not be loaded before child, so this handles that..
53374 module : 'Pman.Tab.projectMgr',
53376 parent : 'Pman.layout',
53377 disabled : false, // or use a function..
53380 * * @param {Object} details about module
53382 register : function(obj) {
53384 Roo.XComponent.event.fireEvent('register', obj);
53385 switch(typeof(obj.disabled) ) {
53391 if ( obj.disabled() ) {
53397 if (obj.disabled) {
53403 this.modules.push(obj);
53407 * convert a string to an object..
53408 * eg. 'AAA.BBB' -> finds AAA.BBB
53412 toObject : function(str)
53414 if (!str || typeof(str) == 'object') {
53417 if (str.substring(0,1) == '#') {
53421 var ar = str.split('.');
53426 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
53428 throw "Module not found : " + str;
53432 throw "Module not found : " + str;
53434 Roo.each(ar, function(e) {
53435 if (typeof(o[e]) == 'undefined') {
53436 throw "Module not found : " + str;
53447 * move modules into their correct place in the tree..
53450 preBuild : function ()
53453 Roo.each(this.modules , function (obj)
53455 Roo.XComponent.event.fireEvent('beforebuild', obj);
53457 var opar = obj.parent;
53459 obj.parent = this.toObject(opar);
53461 Roo.log("parent:toObject failed: " + e.toString());
53466 Roo.debug && Roo.log("GOT top level module");
53467 Roo.debug && Roo.log(obj);
53468 obj.modules = new Roo.util.MixedCollection(false,
53469 function(o) { return o.order + '' }
53471 this.topModule = obj;
53474 // parent is a string (usually a dom element name..)
53475 if (typeof(obj.parent) == 'string') {
53476 this.elmodules.push(obj);
53479 if (obj.parent.constructor != Roo.XComponent) {
53480 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
53482 if (!obj.parent.modules) {
53483 obj.parent.modules = new Roo.util.MixedCollection(false,
53484 function(o) { return o.order + '' }
53487 if (obj.parent.disabled) {
53488 obj.disabled = true;
53490 obj.parent.modules.add(obj);
53495 * make a list of modules to build.
53496 * @return {Array} list of modules.
53499 buildOrder : function()
53502 var cmp = function(a,b) {
53503 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
53505 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
53506 throw "No top level modules to build";
53509 // make a flat list in order of modules to build.
53510 var mods = this.topModule ? [ this.topModule ] : [];
53512 // elmodules (is a list of DOM based modules )
53513 Roo.each(this.elmodules, function(e) {
53518 // add modules to their parents..
53519 var addMod = function(m) {
53520 Roo.debug && Roo.log("build Order: add: " + m.name);
53523 if (m.modules && !m.disabled) {
53524 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
53525 m.modules.keySort('ASC', cmp );
53526 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
53528 m.modules.each(addMod);
53530 Roo.debug && Roo.log("build Order: no child modules");
53532 // not sure if this is used any more..
53534 m.finalize.name = m.name + " (clean up) ";
53535 mods.push(m.finalize);
53539 if (this.topModule) {
53540 this.topModule.modules.keySort('ASC', cmp );
53541 this.topModule.modules.each(addMod);
53547 * Build the registered modules.
53548 * @param {Object} parent element.
53549 * @param {Function} optional method to call after module has been added.
53557 var mods = this.buildOrder();
53559 //this.allmods = mods;
53560 //Roo.debug && Roo.log(mods);
53562 if (!mods.length) { // should not happen
53563 throw "NO modules!!!";
53567 var msg = "Building Interface...";
53568 // flash it up as modal - so we store the mask!?
53569 if (!this.hideProgress) {
53570 Roo.MessageBox.show({ title: 'loading' });
53571 Roo.MessageBox.show({
53572 title: "Please wait...",
53581 var total = mods.length;
53584 var progressRun = function() {
53585 if (!mods.length) {
53586 Roo.debug && Roo.log('hide?');
53587 if (!this.hideProgress) {
53588 Roo.MessageBox.hide();
53590 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
53596 var m = mods.shift();
53599 Roo.debug && Roo.log(m);
53600 // not sure if this is supported any more.. - modules that are are just function
53601 if (typeof(m) == 'function') {
53603 return progressRun.defer(10, _this);
53607 msg = "Building Interface " + (total - mods.length) +
53609 (m.name ? (' - ' + m.name) : '');
53610 Roo.debug && Roo.log(msg);
53611 if (!this.hideProgress) {
53612 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
53616 // is the module disabled?
53617 var disabled = (typeof(m.disabled) == 'function') ?
53618 m.disabled.call(m.module.disabled) : m.disabled;
53622 return progressRun(); // we do not update the display!
53630 // it's 10 on top level, and 1 on others??? why...
53631 return progressRun.defer(10, _this);
53634 progressRun.defer(1, _this);
53648 * wrapper for event.on - aliased later..
53649 * Typically use to register a event handler for register:
53651 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
53660 Roo.XComponent.event = new Roo.util.Observable({
53664 * Fires when an Component is registered,
53665 * set the disable property on the Component to stop registration.
53666 * @param {Roo.XComponent} c the component being registerd.
53671 * @event beforebuild
53672 * Fires before each Component is built
53673 * can be used to apply permissions.
53674 * @param {Roo.XComponent} c the component being registerd.
53677 'beforebuild' : true,
53679 * @event buildcomplete
53680 * Fires on the top level element when all elements have been built
53681 * @param {Roo.XComponent} the top level component.
53683 'buildcomplete' : true
53688 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
53689 //<script type="text/javascript">
53694 * @extends Roo.LayoutDialog
53695 * A generic Login Dialog..... - only one needed in theory!?!?
53697 * Fires XComponent builder on success...
53700 * username,password, lang = for login actions.
53701 * check = 1 for periodic checking that sesion is valid.
53702 * passwordRequest = email request password
53703 * logout = 1 = to logout
53705 * Affects: (this id="????" elements)
53706 * loading (removed) (used to indicate application is loading)
53707 * loading-mask (hides) (used to hide application when it's building loading)
53713 * Myapp.login = Roo.Login({
53729 Roo.Login = function(cfg)
53735 Roo.apply(this,cfg);
53737 Roo.onReady(function() {
53743 Roo.Login.superclass.constructor.call(this, this);
53744 //this.addxtype(this.items[0]);
53750 Roo.extend(Roo.Login, Roo.LayoutDialog, {
53753 * @cfg {String} method
53754 * Method used to query for login details.
53759 * @cfg {String} url
53760 * URL to query login data. - eg. baseURL + '/Login.php'
53766 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
53771 * @property checkFails
53772 * Number of times we have attempted to get authentication check, and failed.
53777 * @property intervalID
53778 * The window interval that does the constant login checking.
53784 onLoad : function() // called on page load...
53788 if (Roo.get('loading')) { // clear any loading indicator..
53789 Roo.get('loading').remove();
53792 //this.switchLang('en'); // set the language to english..
53795 success: function(response, opts) { // check successfull...
53797 var res = this.processResponse(response);
53798 this.checkFails =0;
53799 if (!res.success) { // error!
53800 this.checkFails = 5;
53801 //console.log('call failure');
53802 return this.failure(response,opts);
53805 if (!res.data.id) { // id=0 == login failure.
53806 return this.show();
53810 //console.log(success);
53811 this.fillAuth(res.data);
53812 this.checkFails =0;
53813 Roo.XComponent.build();
53815 failure : this.show
53821 check: function(cfg) // called every so often to refresh cookie etc..
53823 if (cfg.again) { // could be undefined..
53826 this.checkFails = 0;
53829 if (this.sending) {
53830 if ( this.checkFails > 4) {
53831 Roo.MessageBox.alert("Error",
53832 "Error getting authentication status. - try reloading, or wait a while", function() {
53833 _this.sending = false;
53838 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
53841 this.sending = true;
53848 method: this.method,
53849 success: cfg.success || this.success,
53850 failure : cfg.failure || this.failure,
53860 window.onbeforeunload = function() { }; // false does not work for IE..
53870 failure : function() {
53871 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
53872 document.location = document.location.toString() + '?ts=' + Math.random();
53876 success : function() {
53877 _this.user = false;
53878 this.checkFails =0;
53880 document.location = document.location.toString() + '?ts=' + Math.random();
53887 processResponse : function (response)
53891 res = Roo.decode(response.responseText);
53893 if (typeof(res) != 'object') {
53894 res = { success : false, errorMsg : res, errors : true };
53896 if (typeof(res.success) == 'undefined') {
53897 res.success = false;
53901 res = { success : false, errorMsg : response.responseText, errors : true };
53906 success : function(response, opts) // check successfull...
53908 this.sending = false;
53909 var res = this.processResponse(response);
53910 if (!res.success) {
53911 return this.failure(response, opts);
53913 if (!res.data || !res.data.id) {
53914 return this.failure(response,opts);
53916 //console.log(res);
53917 this.fillAuth(res.data);
53919 this.checkFails =0;
53924 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
53926 this.authUser = -1;
53927 this.sending = false;
53928 var res = this.processResponse(response);
53929 //console.log(res);
53930 if ( this.checkFails > 2) {
53932 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
53933 "Error getting authentication status. - try reloading");
53936 opts.callCfg.again = true;
53937 this.check.defer(1000, this, [ opts.callCfg ]);
53943 fillAuth: function(au) {
53944 this.startAuthCheck();
53945 this.authUserId = au.id;
53946 this.authUser = au;
53947 this.lastChecked = new Date();
53948 this.fireEvent('refreshed', au);
53949 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
53950 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
53951 au.lang = au.lang || 'en';
53952 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
53953 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
53954 this.switchLang(au.lang );
53957 // open system... - -on setyp..
53958 if (this.authUserId < 0) {
53959 Roo.MessageBox.alert("Warning",
53960 "This is an open system - please set up a admin user with a password.");
53963 //Pman.onload(); // which should do nothing if it's a re-auth result...
53968 startAuthCheck : function() // starter for timeout checking..
53970 if (this.intervalID) { // timer already in place...
53974 this.intervalID = window.setInterval(function() {
53975 _this.check(false);
53976 }, 120000); // every 120 secs = 2mins..
53982 switchLang : function (lang)
53984 _T = typeof(_T) == 'undefined' ? false : _T;
53985 if (!_T || !lang.length) {
53989 if (!_T && lang != 'en') {
53990 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53994 if (typeof(_T.en) == 'undefined') {
53996 Roo.apply(_T.en, _T);
53999 if (typeof(_T[lang]) == 'undefined') {
54000 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
54005 Roo.apply(_T, _T[lang]);
54006 // just need to set the text values for everything...
54008 /* this will not work ...
54012 function formLabel(name, val) {
54013 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
54016 formLabel('password', "Password"+':');
54017 formLabel('username', "Email Address"+':');
54018 formLabel('lang', "Language"+':');
54019 this.dialog.setTitle("Login");
54020 this.dialog.buttons[0].setText("Forgot Password");
54021 this.dialog.buttons[1].setText("Login");
54040 collapsible: false,
54042 center: { // needed??
54045 // tabPosition: 'top',
54048 alwaysShowTabs: false
54052 show : function(dlg)
54054 //console.log(this);
54055 this.form = this.layout.getRegion('center').activePanel.form;
54056 this.form.dialog = dlg;
54057 this.buttons[0].form = this.form;
54058 this.buttons[0].dialog = dlg;
54059 this.buttons[1].form = this.form;
54060 this.buttons[1].dialog = dlg;
54062 //this.resizeToLogo.defer(1000,this);
54063 // this is all related to resizing for logos..
54064 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
54066 // this.resizeToLogo.defer(1000,this);
54069 //var w = Ext.lib.Dom.getViewWidth() - 100;
54070 //var h = Ext.lib.Dom.getViewHeight() - 100;
54071 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
54073 if (this.disabled) {
54078 if (this.user.id < 0) { // used for inital setup situations.
54082 if (this.intervalID) {
54083 // remove the timer
54084 window.clearInterval(this.intervalID);
54085 this.intervalID = false;
54089 if (Roo.get('loading')) {
54090 Roo.get('loading').remove();
54092 if (Roo.get('loading-mask')) {
54093 Roo.get('loading-mask').hide();
54096 //incomming._node = tnode;
54098 //this.dialog.modal = !modal;
54099 //this.dialog.show();
54103 this.form.setValues({
54104 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
54105 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
54108 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
54109 if (this.form.findField('username').getValue().length > 0 ){
54110 this.form.findField('password').focus();
54112 this.form.findField('username').focus();
54120 xtype : 'ContentPanel',
54132 style : 'margin: 10px;',
54135 actionfailed : function(f, act) {
54136 // form can return { errors: .... }
54138 //act.result.errors // invalid form element list...
54139 //act.result.errorMsg// invalid form element list...
54141 this.dialog.el.unmask();
54142 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
54143 "Login failed - communication error - try again.");
54146 actioncomplete: function(re, act) {
54148 Roo.state.Manager.set(
54149 this.dialog.realm + '.username',
54150 this.findField('username').getValue()
54152 Roo.state.Manager.set(
54153 this.dialog.realm + '.lang',
54154 this.findField('lang').getValue()
54157 this.dialog.fillAuth(act.result.data);
54159 this.dialog.hide();
54161 if (Roo.get('loading-mask')) {
54162 Roo.get('loading-mask').show();
54164 Roo.XComponent.build();
54172 xtype : 'TextField',
54174 fieldLabel: "Email Address",
54177 autoCreate : {tag: "input", type: "text", size: "20"}
54180 xtype : 'TextField',
54182 fieldLabel: "Password",
54183 inputType: 'password',
54186 autoCreate : {tag: "input", type: "text", size: "20"},
54188 specialkey : function(e,ev) {
54189 if (ev.keyCode == 13) {
54190 this.form.dialog.el.mask("Logging in");
54191 this.form.doAction('submit', {
54192 url: this.form.dialog.url,
54193 method: this.form.dialog.method
54200 xtype : 'ComboBox',
54202 fieldLabel: "Language",
54205 xtype : 'SimpleStore',
54206 fields: ['lang', 'ldisp'],
54208 [ 'en', 'English' ],
54209 [ 'zh_HK' , '\u7E41\u4E2D' ],
54210 [ 'zh_CN', '\u7C21\u4E2D' ]
54214 valueField : 'lang',
54215 hiddenName: 'lang',
54217 displayField:'ldisp',
54221 triggerAction: 'all',
54222 emptyText:'Select a Language...',
54223 selectOnFocus:true,
54225 select : function(cb, rec, ix) {
54226 this.form.switchLang(rec.data.lang);
54242 text : "Forgot Password",
54244 click : function() {
54245 //console.log(this);
54246 var n = this.form.findField('username').getValue();
54248 Roo.MessageBox.alert("Error", "Fill in your email address");
54252 url: this.dialog.url,
54256 method: this.dialog.method,
54257 success: function(response, opts) { // check successfull...
54259 var res = this.dialog.processResponse(response);
54260 if (!res.success) { // error!
54261 Roo.MessageBox.alert("Error" ,
54262 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
54265 Roo.MessageBox.alert("Notice" ,
54266 "Please check you email for the Password Reset message");
54268 failure : function() {
54269 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
54282 click : function () {
54284 this.dialog.el.mask("Logging in");
54285 this.form.doAction('submit', {
54286 url: this.dialog.url,
54287 method: this.dialog.method